Google CTF 2017 ascii art writeup
Google CTF 2017 - ASCII Art Writeup
이번에는 리버싱 문제중 하나인 aart 를 풀어 보았다. 결론부터 말하면 허무하게 풀려버렸다;
이번 문제는 바이너리와 패킷 덤프가 주어졌다.
# file aart_client
aart_client: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=220420b2d90546e195ca6df0119e299f3ad28514, stripped
바이너리를 IDA 로 열어보면 protobuf 관련 클래스가 많이 나오는데, 검색해 보니 객체 등의 다양한 자료들을 송수신 하게 해주는 google 에서 만든 라이브러리이며 게임 등 실무에서도 많이 사용된다고 한다.
패킷을 열어보면 바이너리와 서버가 주고 받은 패킷임을 알 수 있는데, 자세히 보면 내용이 동일한 패킷이 주기적으로 보내진 것을 알 수 있다. 아마도 바이너리의 HELLO 문자열과 관련된 패킷일 것으로 생각된다.
즉 HELLO -> Message 전송의 형식으로 통신을 한 것으로 볼 수 있다.
처음엔 바이너리를 좀 분석하다가... 실행하려면 서버가 필요해서 웹서버를 만들어서 시뮬레이션(?) 해 보기로 했고, 아래와 같이 간단히 코딩하여 소켓으로 응답을 돌려줬다.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import SocketServer seq = 0 msg_0 = '''787e7f756d667e7c7c15787e70746d667e7c232b4c5c57405554435d5851555b5549505a554e405b545c4f51405c545b4f5449432b193931''' msg_1 = '''54795e5e2c5d2c2c2c2c2c2c2c2c5e5d135e53535353535353535479535d2f532c5d2c2c2c2c2c2c2c2c5c5d5353135d5353535353535479535d53535353532f5353535353535353535c53535353135d535353535c795353535c53535353532f535353535353535c53535353532f2f5353537953530f53535353535353532f535e545e5e5c1353535353535353535353530f79534e5d5e5e5e5e0d0d0d0d5c0d535353532f530d0d0d0d5e0d5e5e4e5e535d7953492e4949494949490f4953532c5a535b0f5349494949494949495328535354795e4e5e5e5d5e2c2c2c2c532f505353532c5c2c2c5d2c5e5e5e5e134e53530f7953535e0d2c5d5353532f58535e5e585e535353535353535353530f53535354795d5e532c53530d535d5e5c53530f53532f0f535353535353535c5c5353537953530f5d535e542c5d53535c530f5353530f532f534e54134e53535d0d535353530f7953530f530d5d53535c535353530f5353530f2f532c2c0d535c5d535353537953530f53532f0f5d535e5e530d0f5353530f5353535e0d5d5e5c535353535353532f795c2c5353532f53532c530f2c53530f532c2c53535353535c5353535353532c7953535353532f53535353530f5353530f53535353535c53535353535379532f2f53530f0f2c2c0f2c530f5c53535c53535353535353532f79532f0f0f53530f53530f5c5c535353535353535353532f790f2f530f53530f0f5c5c5353535353535353535379532c2f530f53532c0f535c535353535353535353537953532c53535353532c5353535353535353535353537979b97716690a061e1d171f1b091112031f101f041a111f160a1b1e1605110a1e1e0905530370617b''' msg_2 = '''787e7f756d667e7c7c15787e70746d667e7c232b4e564150525b5d5e57504b5e48405558534158505141494a564d515848564b562b193931''' msg_3 = '''037e6c612e496c67446c3c2e7168746c772e6c6c2e65667a6d686e6c652e2e6c6c772e6f2e6262702e746277576b457840571931746c7b6a686167646d6a7164727a6f62697b626a6b7b73706c776b62726c716c11230b7a''' msg_4 = '''787e7f756d667e7c7c15787e70746d667e7c232b53545f485c515349545449564e4f4f554353485a4d504e4d50404d545c5c514f2b193931''' msg_5 = '''54795e5e2c5d2c2c2c2c2c2c2c2c5e5d135e53535353535353535479535d2f532c5d2c2c2c2c2c2c2c2c5c5d5353135d5353535353535479535d53535353532f5353535353535353535c53535353135d535353535c795353535c53535353532f535353535353535c53535353532f2f5353537953530f53535353535353532f535e545e5e5c1353535353535353535353530f79534e5d5e5e5e5e0d0d0d0d5c0d535353532f530d0d0d0d5e0d5e5e4e5e535d7953492e4949494949490f4953532c5a535b0f5349494949494949495328535354795e4e5e5e5d5e2c2c2c2c532f505353532c5c2c2c5d2c5e5e5e5e134e53530f7953535e0d2c5d5353532f58535e5e585e535353535353535353530f53535354795d5e532c53530d535d5e5c53530f53532f0f535353535353535c5c5353537953530f5d535e542c5d53535c530f5353530f532f534e54134e53535d0d535353530f7953530f530d5d53535c535353530f5353530f2f532c2c0d535c5d535353537953530f53532f0f5d535e5e530d0f5353530f5353535e0d5d5e5c535353535353532f795c2c5353532f53532c530f2c53530f532c2c53535353535c5353535353532c7953535353532f53535353530f5353530f53535353535c53535353535379532f2f53530f0f2c2c0f2c530f5c53535c53535353535353532f79532f0f0f53530f53530f5c5c535353535353535353532f790f2f530f53530f0f5c5c5353535353535353535379532c2f530f53532c0f535c535353535353535353537953532c53535353532c5353535353535353535353537979b9771e6902191b1503161e191c1e05031f04190510091a0207070a041e1a16070516531b70617b''' msgs = [msg_0, msg_3, msg_2, msg_1, msg_4, msg_5] class S(BaseHTTPRequestHandler): def _set_headers(self): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() def do_GET(self): self._set_headers() self.wfile.write("<html><body><h1>hi!</h1></body></html>") def do_HEAD(self): self._set_headers() def do_POST(self): # Doesn't do anything with posted data global seq self._set_headers() print self.rfile.read(int(self.headers['Content-Length'])) self.wfile.write(msgs[seq]) seq += 1 def run(server_class=HTTPServer, handler_class=S, port=80): server_address = ('', port) httpd = server_class(server_address, handler_class) print 'Starting httpd...' httpd.serve_forever() if __name__ == "__main__": from sys import argv if len(argv) == 2: run(port=int(argv[1])) else: run()
그러자... 아스키 비행기가 나왔다.
# ./aart_client 127.0.0.1
_ _
/_| |_\
//|| ||\\
// || || \\
// ||___|| \\
/ | | \ _
/ __| |__ \ /_\
/ .--~ | | ~--. \| |
/.~ __\ | | / ~.| |
.~ `=='\ | | / _.-'. |
/ / \| |/ .-~ _.-'
| +---+ \ _.-~ |
`=----.____/ # \____.----='
[::::::::| (_) |::::::::]
.=----~~~~~\ /~~~~~----=.
| /`---'\ |
\ \ / \ / /
`. / \ .'
`. /._________.\ .'
`--._________.--'
그리고...몇번 더 실행해보니 플래그가 나왔다 -_-;;;;;
# ./aart_client 127.0.0.1
CTF{That-was-a-lot-of-monkey-foot-work?-Good-Job!}
다른 풀이를 찾아보니 이건 꼼수고.. 제대로 된 풀이는 protobuf 프로토콜을 분석해서 flag 헥스값을 디코딩해서 키를 추출하는 식이었다. 어쨌든 풀었으니 이건 다음에 -_-;
'CTF Writeup' 카테고리의 다른 글
0ctf 2018 - LoginMe Writeup (0) | 2018.04.10 |
---|---|
codegate 2018 miro writeup (0) | 2018.02.06 |
codegate 2018 Impel Down writeup (0) | 2018.02.06 |
codegate 2018 - rbsql writeup (0) | 2018.02.06 |
Codegate 2017 - babypwn (0) | 2017.02.28 |