强网杯精英赛web题题解

0x01 信息搜集

登录进去之后,打印了用户名(被addslashes过),还有ip,ip经过测试之后可以通过xff头进行伪造,然后有一个上传点,另外登录的用户名给他传个数组会出现报错信息,

qwbjy

另外这里phpsessid清空之后也会有报错信息

qwbjy2

不过这些报错信息似乎是用途不大暂时。

另外用户名这里在前端只能输入长度20,如果要超过20长度需要抓包修改

初步的信息搜集之后,发现用户名出似乎没有注入和二次注入,xff头那里过滤了一些/,*'等特殊字符,另外空格被匹配替换了,说明这里进行了特殊处理。但是具体怎么利用还需要后续分析。

然后就是上传点

0x02 突破上传

简单测试之后,发现上传的文件如果不是php文件就是返回i need php file,如果是php文件就返回attack detected,那服务器究竟是怎么判断这个到底是不是php文件的呢?

经过一番fuzz,猜测是用的mime_content_type或是fileinfo函数,那么,另外如果那边判断确实是x-php文件之后,如果文件头是<?就仍然上传不上去。

那么思路就很清晰了,就是上传一个文件开头不是<?,但是mime_content_type或是fileinfo函数判断它还是x-php类型的文件,

这个时候BOM头就起作用了。

然后我们测试如下payload,

qwbjy3

这里上传内容的hex值如下:

qwbjy4

这样子,mime_content_type或是fileinfo能够返回text/x-php,而前两个字符也不是<?

这样子txt,就能上传了,然后fuzz了一下,发现文件后缀为php7或是php+空格时可以上传成功。这里服务器的php版本是5,所以php7显然不行,那就另一个了。

上传成功之后,发现打印了一串长度位10的东西,尝试编码解码之类的都不行,这个应该和上传之后的文件名相关的。

0x03 注入

首先根据搜集的信息,我们发现,当username过长时我们上传成功之后会看不到上传结果就是那个10字节的东西,那么猜测初始登录username仅存在session中,在上传成功之后入库时,将session中的username进行了截断,经过fuzz之后发现截断长度是20。

其中入库的时候ip也要入库,也就是我们可以伪造的xff头,但是这个xff头不能引入单引号没法儿直接注入,但是我们的用户名是被转义过得,用户名0123456789012345678',那么session里面就会存储0123456789012345678\',这样截断的时候留下了转义符号,然后就能在拼接的时候转义掉单引号,从而引入了一个单引号,触发xff的注入。

所以以用户名0123456789012345678',然后如下

qwbjy5

然后就能注入了,insert的回显注入,回显的内容在账户0123456789012345678',下面这个就不用多说了。

每次回显10位依次拿到

库名:challenge
表名:picture
列名:id,name,ipaddr,filename

然后到这里应该就知道了完整的文件名在数据库里面,只回显10位所以看不全,需要通过注入获取完整的数据。

这里注意一个问题,在insert语句中无法直接从当前表select数据,需要引入别名,tip如下:

mysql> insert into picture values('123',(select filename from picture limit 1));
ERROR 1093 (HY000): You can't specify target table 'picture' for update in FROM clause

mysql> insert into picture values('123',(select filename from (select filename from picture)`a` limit 1));
Query OK, 1 row affected (0.01 sec)

这样就能够在insert的时候从当前表中查询出数据了 这里在子查询中由于不能使用空格导致limit无法使用,需要限定返回仅一列,否则会报错,like也被过滤,考虑regexp进行条件限定,限定就是

select mid(filename,11,10) from (select filename from `picture` where filename regexp 'JpH4G4CQaG.*') as `a`

最后构造一下绕过过滤即可,最后的payload

,11111,(select(mid(filename,11,10))from(select(filename)from(`picture`)where((filename)regexp( CHAR(118,53,51,56,75,88,99,72,51,121,46,42))))as`a`))#

然后把11依次替换21,31,42,51,61,71,….把完整的文件名爆出来

如下:

qwbjy6

拼接得到完整文件名

JpH4G4CQaG5tCTNe7eVsFbeNfWNcE76NWdi2GkjhrNau6n8D0tv649jIwxk_4PNq.php

访问http://xxxx/uploads/ JpH4G4CQaG5tCTNe7eVsFbeNfWNcE76NWdi2GkjhrNau6n8D0tv649jIwxk_4PNq.php 成功getshell,图如下:

qwbjy7

最后膜一下蛋总和出题师傅