BUUCTF_Web题目题解记录1

刷题Web篇
【BUUCTF_Web题目题解记录1】文章目录
前言
在无脑刷了若干题目后,回过头来整理,所以顺序和内容比较随缘 。
就不写解题过程了,直接说用到的方法和答案 。
总是想无脑刷题而不去归纳总结、一味地忍不住去和同事卷解题数量就是自己欺骗自己啊,要真的学到东西才行的 。
一、[]
这是一道SQL注入的题,输入1,1’ or 1=1#,1’ order by 2#这些都是有返回内容的,然后尝试联合注入的时候发现被过滤,没招了,查了别人的wp得知要使用“堆叠注入” 。
堆叠注入?应该就是用;来分割可以执行的语句吧
1.查表名:1’;show #
得知有一个叫的表,想到继续尝试得到这个表中的列名 。
2.查列名:1’;showfrom #
果然有一个叫flag的列,下面就是要去拿到flag列里的字段了
这里意外发现把from换成in也可以哈哈哈
其实这个网页点了提交之后,输入框就会只剩下个1,然后截图看起来就好怪!所以上一张截图在语句消失后我又手动敲上了,但后面不想敲了emmm
3.获取字段
由于这题过滤了,所以又做不动了,查看别人的wp得知要用 。
语法是:
open … 获取句柄
… read first 读取第一行数据
… read next 读取下一行数据
这里的三处…是自己可以随意命名的“句柄”,保持一致即可
这里用:1’;open fh; fh read first#
拿到flag!
二、[网鼎杯 2020 青龙组]
打开靶机之后是PHP代码:
process();}public function process() {if($this->op == "1") {$this->write();} else if($this->op == "2") {$res = $this->read();$this->output($res);} else {$this->output("Bad Hacker!");}}private function write() {if(isset($this->filename) && isset($this->content)) {if(strlen((string)$this->content) > 100) {$this->output("Too long!");die();}$res = file_put_contents($this->filename, $this->content);if($res) $this->output("Successful!");else $this->output("Failed!");} else {$this->output("Failed!");}}private function read() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);}return $res;}private function output($s) {echo "[Result]:
";echo $s;}function __destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}}function is_valid($s) {for($i = 0; $i < strlen($s); $i++)if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))return false;return true;}if(isset($_GET{'str'})) {$str = (string)$_GET['str'];if(is_valid($str)) {$obj = unserialize($str);}}

这题考察的是反序列化
从题目给出代码的最后可以看出,是以GET方式传入序列化的str字符串,要求str字符串中每一个字符的ASCII码范围在32到125之间,也就是在校验输入是可见字符,然后对其反序列化 。
通过看别人的wp,得知
在反序列化的过程中,调用()析构方法
function __destruct() {if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}
可以看到在()中,如果op===“2”,则将其赋值为"1",同时赋值为空,然后执行(),需要注意到的地方是,这里op与"2"的比较是强类型比较===
public function process() {if($this->op == "1") {$this->write();} else if($this->op == "2") {$res = $this->read();$this->output($res);} else {$this->output("Bad Hacker!");}}
在()中,如果op==“1”,执行write(),如果op==“2”,则执行read(),否则输出“Back ”,可以看出来这里op与字符串的比较变成了弱类型比较==
所以,我们只要令op=2,这里的2是整数int,便可以满足op==="2"为false,保证op不会在析构方法()中被置1,op=="2"为true,可以在()中去执行read()
private function read() {$res = "";if(isset($this->filename)) {$res = file_get_contents($this->filename);}return $res;}
read()中用函数读取文件,我们此处借助php://伪协议读取文件,是我们可以控制的 。read()执行完后,使用()输出读取到的内容 。
还有一个需要注意的地方是,$op,$,$三个变量权限都是,而权限的变量在序列化时会有*字符,字符的ASCII码为0,就无法通过上面的函数校验 。
这里最简单的一种绕过方法是:php7.1+版本对属性类型不敏感,本地序列化的时候将属性改为进行绕过即可:
public $op=2;public $filename="php://filter/read=convert.base64-encode/resource=flag.php";public $content;
可以找个能在线运行php的网页,放进去如下代码,运行

运行得到的结果是:
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
在题目url后面接上?str=上面的运行结果,敲回车
然后下拉滚动条,在网页最下方可以看到一串经编码后的输出,对其做解码即可得到flag 。这里我当时是用的的模块来解码的,也可以找一个在线网站对解码,有插件的也可以借助插件来做解码 。
在命令行用做解码:
本题参考:
三、[]
这道题考的是文件上传
直接说最终的结论:
1.过滤了文件后缀中的ph,所以php、phtml这些后缀名都不可用了,只能再去试试png、jpg这些 。png也不行,提示“类型露骨”,jpg则可以上传 。
2.既然上传的是jpg而非php,要想利用的话,就要设法使服务器端将jpg文件解析为php文件 。这里需要再上传一个文件.
.的内容可以是:
SetHandler application/x-httpd-php
或者:
AddType application/x-httpd-php .jpg
再或者:
SetHandler application/x-httpd-php
3.上传.时,由于我是用的macOS,不能以.作为文件名,所以命名为1.,开burp拦截再将文件名修改为.,并且要修改-Type是image/jpeg,上传成功后,可以用中国蚁剑连接 。
另外要注意的是,在上传的jpg中,如果有