0%

moectfwp

前言:打了两个月的moectf,写一个wp

MISC

1.signin

一开始打开环境不知道怎么做,直到看到WSRX出现,上网一查原来是WebSocket(网络通信协议),然后根据地址(Releases · XDSEC/WebSocketReflectorX (github.com))下载之后启动,输入地址后会给你一个地址,再再浏览器输入该地址你就会得到如下页面:

image-20241008210311069

根据题目描述,luo同学是缺勤行为,所以只需要将”教师代签”改为”缺勤”,其他同学全改为教师代签即可弹出flag

2.罗小黑战记

下载之后发现是gif图,那么使用WPS的gif动图制作,可以将gif分解成一张一张图,最终找出其中的二维码,扫一扫flag就出来了

3.杂项入门指北

flag就在海报中

image-20241008210652528

放大来看就能发现右边的线是不连续的,那么应该是摩斯密码,对照摩斯密码表就能得出flag

4.so many ‘m’

打开题目发现是很乱的文字,第一次做还真做不出来,问了学长之后才知道跟字频有关,上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def calculate_char_frequency_and_sort(s):
# 创建一个空字典来存储字符及其频率
char_freq = {}

# 遍历字符串中的每个字符
for char in s:
# 更新字符频率
char_freq[char] = char_freq.get(char, 0) + 1

# 根据频率(降序)和字典顺序(升序ASCII,用于相同频率的字符)对字符进行排序
# 注意:由于我们是对字典的键进行排序,而字典键在Python 3.7+中是有序的(基于插入顺序),
# 但这里我们实际上关心的是排序后的结果,所以不需要担心原始插入顺序。
sorted_chars = sorted(char_freq.items(), key=lambda item: (-item[1], item[0]))

# 如果你只想输出排序后的字符(不包括频率),可以这样做:
sorted_chars_only = ''.join(char for char, freq in sorted_chars)
return sorted_chars_only


# 示例字符串
example_string = "a!{ivlotzkEm{CtsvEpbDkwexsotyMuECs!mvlhmenrhwpMh0leydsMbC#CC}sii}tkb}ugCD{zlEeT#kyC0fbukglpopmaekbEthmjcMdsgkvmTnC}eot#dcf{ec@ccgqpfqMycysMuuou!en#{g0cDmoyxTCMgt{joT{jnl0rhoklCe{n0CnxprydeaTg0r{avkEjckjEsxhaohs{Trbkr!ffqip444uwrc}nnevgtCT{jCipogtipzdeDiqsy44rMfj{MzCw#qwg{T4m{cuk!hwuncxdmddeurtsojakrjC#vTDd}0poTT@c!DftjwuDp@mcuheeDtfao!iEcEq}kcf#Mpcam{mml4i4mpDnedamcwtC0nem{mDotnmp4jf@TpxfqMoiqwtdijDfimmCzmxe#gsTu{poeTEhD!u0anvTTTbbi{q}zapcksMifDlovoeac@{0keh0dg{Mi!@tfftqitmuMoMcuTpmcgnmozyrrv#zfmzmetyxxa0wczE}eoD{xcMnoCuebu0otdusiDknfvo0{fEsMftzT!eoslegbypspC4vkxm#uaf@acuemhMyiDou#at0rfl4a}0ixeEktws}pMCfCigaTafg}ffssmwwuTkTuls0{M@c4e@{D{tuorzmyqptChpngkeCohCCMTwqctinc0mcjemclv@cMoqf00poarte@oqmuysm#mo{et4kcCpcgcT}vD}m!g4{E0!Mol0fpo!{srT0pf{cMuCx0bp{ftTmExcrn}0etonez!@C4tfa4aM00siztb@fomfD#{#tMbo@jgb4CM0dEk0tea4aMCafn"

# 计算并打印排序后的字符序列
sorted_chars = calculate_char_frequency_and_sort(example_string)
print(sorted_chars) # 输出应该是 'abnn' 或类似的,具体取决于Python版本和实现细节(但在这个例子中应该是'abnn')

5.Abnormal lag

这首歌的一开始和结尾确实有些不一样,那猜测是音频隐写,用Audacity打开,因为是音不一样了,所以改成频谱图,就能找到flag(格式是uuid)

逆向工程

1.逆向工程入门指北

解密脚本跑一下就出来了

2.xor

用ida64位打开之后F5找到main函数,就是一个简单的异或操作,将入门指北的解密脚本修改一下就可以拿来用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
int main()
{
char password_enc[] = {73,75,65,71,80,66,95,65,28,22,70,16,19,28,64,9,66,22,70,28,9,16,16,66,29,
9,70,21,20,20,9,23,22,20,65,64,64,22,20,71,18,64,20,89 };
// 因为a^b=c时, b^c=a, 所以我们可以这样还原数据:
char password[45];
for (int i = 0; i < 44; i++) {
password[i] = password_enc[i] ^ 36;
}
password[46] = 0; // 使用0字符来截断掉%s的无尽输出..
printf("%s\n", password); // 哈哈,这就是本题的f l a g,自己运行一下交上去吧!
return 0;
}

3.upx

将文件拖入DIE64位查看有upx加壳

image-20241008211033384

用upx脱壳

upx -d 文件地址

再用ida64打开就有flag

4.dynamic

用x64dbg打开文件,题目比较友好,给我们设置好了断点,所以我们只需要在断点位置出发,单步步过几次flag就能显现出来

image-20241008212100168

5.upx-revenge

用DIE查看是upx脱壳

脱壳试试看,发报错

image-20241008212229509

大约意思是:文件被修改/被黑客攻击/保护

那么就用DIE自带的Hex查看器查看16进制

image-20241008212406339

对比正常的upx加壳的区别发现vmp0,vmp1

看来是修改了upx的区段名,改回来保存再脱壳,用IDA打开就能看到flag

image-20241008212530064

6.TEA

IDA打开F5查看main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // r9d
unsigned int v4; // r8d
unsigned int v5; // edx
__int64 v6; // r10
char *v7; // rcx
int v9; // [rsp+20h] [rbp-28h]
unsigned int v10; // [rsp+28h] [rbp-20h]
int v11; // [rsp+2Ch] [rbp-1Ch]

sub_140001020("moectf{xxxxxxxx-yyyy-zzzz-9c42-caf30620caaf}\nxxxxxxxx=");
sub_140001080("%8x");
sub_140001020("yyyy=");
sub_140001080("%4x");
sub_140001020("zzzz=");
sub_140001080("%4x");
v3 = 0;
v4 = v10;
v5 = v9 | (v11 << 16);
v6 = 32i64;
do
{
v3 -= 1640531527;
v4 += (v5 + v3) ^ (16 * v5 + 1702060386) ^ ((v5 >> 5) + 1870148662);
v5 += (v4 + v3) ^ (16 * v4 + 1634038898) ^ ((v4 >> 5) + 1634038904);
--v6;
}
while ( v6 );
if ( v4 != 676078132 || (v7 = "correct flag!!!\n", v5 != 957400408) )
v7 = "not correct, try again!\n";
sub_140001020(v7);
return 0;
}

TEA是一种微型堆成加密算法。它使用一个128位的密钥和64位的明文块,通过多轮迭代加密来实现加密过程。不过这道题就算不知道TEA加密算法也可以做,只需要分析代码然后写出逆过程就好了,不难。

当时还不会python,所以用的是C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
#include<stdint.h>
int main()
{
unsigned int v4 = 676078132,v5 = 957400408,v10 = 0;
int v3 = -52497008864;
for(int v6 = 32;v6 != 0;--v6)
{
v5 -= (v4 + v3) ^ (16 * v4 + 1634038898) ^ ((v4 >> 5) + 1634038904);
v4 -= (v5 + v3) ^ (16 * v5 + 1702060386) ^ ((v5 >> 5) + 1870148662);
v3 += 1640531527;
}
v10 = v4;
printf("v10 = %x,v5 = %x",v10,v5);
}

最终得到的v10和v5就是x,y,z的值,多试几次就对了

7.dotNet

放入脱壳软件发现是.NET,可能是由C#语言编写的文件,放入ILSpy来反汇编

image-20241009202147093

观察代码逻辑主要是中间if语句:先+114然后与0x72异或再和(i * i)异或来判断输入的flag能不能与对应的array相等,所以写一个逆向的程序不难

注意一下,array中的元素经过逆向之后的结果可能不在(0~255)中,所以我们需要加上256然后再对256求余数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
array = [
173, 146, 161, 174, 132, 179, 187, 234, 231, 244,
177, 161, 65, 13, 18, 12, 166, 247, 229, 207,
125, 109, 67, 180, 230, 156, 125, 127, 182, 236,
105, 21, 215, 148, 92, 18, 199, 137, 124, 38,
228, 55, 62, 164
]

decrypted_bytes = bytearray()

for i in range(len(array)):
# 解密字节
decrypted_byte = (array[i] ^ (i * i) ^ 0x72) - 114

# 确保字节值在有效范围内 (0-255)
decrypted_byte = (decrypted_byte + 256) % 256

# 添加解密后的字节到字节数组
decrypted_bytes.append(decrypted_byte)

# 打印解密后的字节数组以便调试
print(f"解密后的字节数组: {decrypted_bytes}")

# 尝试解码并处理可能的解码错误
try:
decrypted_flag = decrypted_bytes.decode('utf-8')
except UnicodeDecodeError as e:
print(f"UnicodeDecodeError: {e}")
# 尝试使用 'latin-1' 编码作为替代
try:
decrypted_flag = decrypted_bytes.decode('latin-1')
except Exception as e:
decrypted_flag = f"解码失败: {e}"

print(f"解密后的字符串: {decrypted_flag}")

8.rc4

.tar.gz是一种再Linux/Unix下常见的压缩文件后缀,再Windows下终端输入tar -xzvf rc4.elf.tar.gz就能解压,再用ida打开,在字串中找到RC4_1s_4w3s0m3对应地址下的函数,F5进入,分析函数能知道密钥就是”A71A68ECD82711CC8C9B16155CD2673E82ADCE75D4BC5756C28A52B86BD6CCF8A4BA722FE05715B92411”,那密钥呢?很好找,就是一开始的RC4_1s_4w3s0m3,在CyberChef (gchq.github.io)网站解密,如图:

image-20241009210052553

9.Reverse进阶之北

文章代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void flag_encryption(unsigned char* input)
{
size_t len = strlen((const char*)input);
if (len != 44)
{
std::cout << "length error!";
return;
}
unsigned int* p = (unsigned int*)input;
for (int i = 0; i < 11; i++)
{
*(p + i) = (*(p + i) * 0xccffbbbb + 0xdeadc0de) ^ 0xdeadbeef + 0xd3906;
std::cout << ", 0x" << std::hex << *(p + i) << ' ';
}
std::cout << std::endl;
// 0xb5073388 , 0xf58ea46f , 0x8cd2d760 , 0x7fc56cda , 0x52bc07da , 0x29054b48 , 0x42d74750 , 0x11297e95 , 0x5cf2821b , 0x747970da , 0x64793c81
}
int main()
{
unsigned char a[] = "moectf{f4k3__flag__here_true_flag_in_s3cr3t}";
flag_encryption(a);
return 0;
}

分析一下代码:将输入的内容按照每四个字节的方式加密,一共有11个。分析一下加密过程就能写出解密的代码了(PS:加法的优先级大于异或,所以写解密代码的时候是将带解密字符与0xccffbbbb + 0xdeadc0de的结果异或)

解密代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
def decrypt_int(encrypted_int):
decrypted_int = (((encrypted_int ^ (0xdeadbeef + 0xd3906)) - 0xdeadc0de) * 0x8d61d173) % 2**32
return decrypted_int
# 加密后的数据(作为整数列表)
encrypted_ints = [
0xb5073388, 0xf58ea46f, 0x8cd2d760, 0x7fc56cda, 0x52bc07da,
0x29054b48, 0x42d74750, 0x11297e95, 0x5cf2821b, 0x747970da, 0x64793c81]
# 解密每个整数
decrypted_ints = [decrypt_int(x) for x in encrypted_ints]

# 打印解密后的结果
for i, decrypted_int in enumerate(decrypted_ints):
print(f"Decrypted int {i + 1}: {decrypted_int:08x}")

现代密码学

1.现代密码学入门之北

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Util.number import bytes_to_long, getPrime
from secret import flag
p = getPrime(128)
q = getPrime(128)
n = p*q
e = 65537
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f"n = {n}")
print(f"p = {p}")
print(f"q = {q}")
print(f"c = {c}")
'''
n = 40600296529065757616876034307502386207424439675894291036278463517602256790833
p = 197380555956482914197022424175976066223
q = 205695522197318297682903544013139543071
c = 36450632910287169149899281952743051320560762944710752155402435752196566406306
'''

这就是典型的RSA加密:

  • 选取两个互质的数,分别记作p和q,则n = p * q,n 是公钥和私钥共有的一部分。
  • 根据欧拉函数,生成phi_n用来表示不大于n并且和n互质的数phi_n = (p - 1) * (q -1),同时phi_n是p和q的最小公倍数
  • 选取另一个公钥e,这个数要满足两个条件:1、1 < e < phi_n;2、gcd(e,phi_n) = 1
  • 加密过程就是:明文 = 密文^e^mod n
  • 当我们需要解密的时候,已知n还需要知道另一个私钥d,这个d同样也满足两个条件:1、1 < d < phi_n 2、e * d = 1 (mod phi_n)
  • 解密过程就是:密文 = 明文^d^mod n

我们知道这个原理,那么就可以很轻松的写出解密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 已知值
p = 197380555956482914197022424175976066223
q = 205695522197318297682903544013139543071
e = 65537
c = 36450632910287169149899281952743051320560762944710752155402435752196566406306

# 计算 phi_n
phi_n = (p - 1) * (q - 1) #与e互质

# 计算私钥 d
d = pow(e, -1, phi_n) #e * d = 1 (mod phi_n)

# 解密
m = pow(c,d,p * q)
flag_bytes = m.to_bytes((m.bit_length() + 7) // 8, 'big')
print(flag_bytes.decode())
print("m =",m)

2.Signin

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from Crypto.Util.number import*
from secret import flag


m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p*q #公钥私钥都有的部分
e = 65537 #公钥幂的部分
c = pow(m,e,n) #密文
pq = (p-1)*(q-2)
qp = (q-1)*(p-2)
p_q = p + q


print(f"{c = }")
print(f"{pq = }")
print(f"{qp = }")
print(f"{n = }")
print(f"{p_q = }")
'''
c = 5654386228732582062836480859915557858019553457231956237167652323191768422394980061906028416785155458721240012614551996577092521454960121688179565370052222983096211611352630963027300416387011219744891121506834201808533675072141450111382372702075488292867077512403293072053681315714857246273046785264966933854754543533442866929316042885151966997466549713023923528666038905359773392516627983694351534177829247262148749867874156066768643169675380054673701641774814655290118723774060082161615682005335103074445205806731112430609256580951996554318845128022415956933291151825345962528562570998777860222407032989708801549746
pq = 18047017539289114275195019384090026530425758236625347121394903879980914618669633902668100353788910470141976640337675700570573127020693081175961988571621759711122062452192526924744760561788625702044632350319245961013430665853071569777307047934247268954386678746085438134169871118814865536503043639618655569687154230787854196153067547938936776488741864214499155892870610823979739278296501074632962069426593691194105670021035337609896886690049677222778251559566664735419100459953672218523709852732976706321086266274840999100037702428847290063111455101343033924136386513077951516363739936487970952511422443500922412450462
qp = 18047017539289114275195019384090026530425758236625347121394903879980914618669633902668100353788910470141976640337675700570573127020693081175961988571621759711122062452192526924744760561788625702044632350319245961013430665853071569777307047934247268954386678746085438134169871118814865536503043639618655569687077087914198877794354459669808240133383828356379423767736753506794441545506312066344576298453957064590180141648690226266236642320508613544047037110363523129966437840660693885863331837516125853621802358973786440314619135781324447765480391038912783714312479080029167695447650048419230865326299964671353746764860
n = 18047017539289114275195019384090026530425758236625347121394903879980914618669633902668100353788910470141976640337675700570573127020693081175961988571621759711122062452192526924744760561788625702044632350319245961013430665853071569777307047934247268954386678746085438134169871118814865536503043639618655569687534959910892789661065614807265825078942931717855566686073463382398417205648946713373617006449901977718981043020664616841303517708207413215548110294271101267236070252015782044263961319221848136717220979435486850254298686692230935985442120369913666939804135884857831857184001072678312992442792825575636200505903
p_q = 279533706577501791569740668595544511920056954944184570513187478007551195831693428589898548339751066551225424790534556602157835468618845221423643972870671556362200734472399328046960316064864571163851111207448753697980178391430044714097464866523838747053135392202848167518870720149808055682621080992998747265496
'''

这个RSA加密算法跟入门之北有一点不一样的是没有直接告诉你p和q的值,但是却告诉了相关的式子,所以只需要进行简单的数学运算就能分别解出p和q的值

解密代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import libnum
p = 101195416461091716428326199733504078281010548412226222689665080411126731520752210150756388683557219973649948209094722629248795549538890771346214761833764975454769057589710497693291150424006859232283601953197097456280805871953601208233200402046794268614613979577032173301390416040533984248749301081715040789947
q = 178338290116410075141414468862040433639046406531958347823522397596424464310941218439142159656193846577575476581439833972909039919079954450077429211036906580907431676882688830353669165640857711931567509254251656241699372519476443505864264464477044478438521412625815994217480304109274071433871779911283706475549
n = 18047017539289114275195019384090026530425758236625347121394903879980914618669633902668100353788910470141976640337675700570573127020693081175961988571621759711122062452192526924744760561788625702044632350319245961013430665853071569777307047934247268954386678746085438134169871118814865536503043639618655569687534959910892789661065614807265825078942931717855566686073463382398417205648946713373617006449901977718981043020664616841303517708207413215548110294271101267236070252015782044263961319221848136717220979435486850254298686692230935985442120369913666939804135884857831857184001072678312992442792825575636200505903
c = 5654386228732582062836480859915557858019553457231956237167652323191768422394980061906028416785155458721240012614551996577092521454960121688179565370052222983096211611352630963027300416387011219744891121506834201808533675072141450111382372702075488292867077512403293072053681315714857246273046785264966933854754543533442866929316042885151966997466549713023923528666038905359773392516627983694351534177829247262148749867874156066768643169675380054673701641774814655290118723774060082161615682005335103074445205806731112430609256580951996554318845128022415956933291151825345962528562570998777860222407032989708801549746
e = 65537

#解出phi_n
phi_n = (p - 1) * (q - 1)

#解出私钥d
d = pow(e,-1,phi_n)

#解出明文
m = pow(c,d,n)
s = libnum.n2s(int(m))

print("s= ",s)

3.ez hash

1
2
3
4
5
6
7
8
9
10
11
from hashlib import sha256
from secret import flag, secrets

assert flag == b'moectf{' + secrets + b'}'
assert secrets[:4] == b'2100' and len(secrets) == 10
hash_value = sha256(secrets).hexdigest()
print(f"{hash_value = }")
# hash_value = '3a5137149f705e4da1bf6742e62c018e3f7a1784ceebcb0030656a2b42f50b6a'


moectf{'2100132768'}

哈希算法,用hashcat暴力破解:hashcat -m 1400 -a hash.txt '2100?d?d?d?d?d?d'

4.Big and small

这又是一道RSA加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from secret import flag
from Crypto.Util.number import*
m = long_to_bytes(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p*q
e = 3
c = pow(m,e,n)

c = 150409620528288093947185249913242033500530715593845912018225648212915478065982806112747164334970339684262757
e = 3
n = 20279309983698966932589436610174513524888616098014944133902125993694471293062261713076591251054086174169670848598415548609375570643330808663804049384020949389856831520202461767497906977295453545771698220639545101966866003886108320987081153619862170206953817850993602202650467676163476075276351519648193219850062278314841385459627485588891326899019745457679891867632849975694274064320723175687748633644074614068978098629566677125696150343248924059801632081514235975357906763251498042129457546586971828204136347260818828746304688911632041538714834683709493303900837361850396599138626509382069186433843547745480160634787

#计算phi_n
phi_n = (p - 1) * ( q - 1)

#计算私钥d

d = pow(e, -1, phi_n)

#解密
m = pow(c,d,n)

这道题也有些不一样的是:没有告诉p和q的值,而且n的值非常大,没有办法算出p和q的具体值。其实对比一下也能发现,c(密文)远小于n,并且e很小。对于这种题目的特殊的特殊解法叫做”小加密指数爆破”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#当n的e次方小于c时
from gmpy2 import *
from Crypto.Util.number import *

n = 20279309983698966932589436610174513524888616098014944133902125993694471293062261713076591251054086174169670848598415548609375570643330808663804049384020949389856831520202461767497906977295453545771698220639545101966866003886108320987081153619862170206953817850993602202650467676163476075276351519648193219850062278314841385459627485588891326899019745457679891867632849975694274064320723175687748633644074614068978098629566677125696150343248924059801632081514235975357906763251498042129457546586971828204136347260818828746304688911632041538714834683709493303900837361850396599138626509382069186433843547745480160634787
e = 0x3
c = 150409620528288093947185249913242033500530715593845912018225648212915478065982806112747164334970339684262757

n = int(n)
e = int(e)
c = int(c)

m = iroot(c, e)
if m[1]:
m = m[0]
print(long_to_bytes(m))

当n的e次方小于c时,相关的解密代码附上,以便下次使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#当n的e次方小于c时
# coding:utf-8
# 小明文攻击
# 适用情况:e较小,一般为3
# 公钥e很小,明文m也不大的话,于是m^e=k*n+m 中的的k值很小甚至为0,爆破k或直接开三次方即可。
import gmpy2, binascii, libnum, time

n = 0xB0BEE5E3E9E5A7E8D00B493355C618FC8C7D7D03B82E409951C182F398DEE3104580E7BA70D383AE5311475656E8A964D380CB157F48C951ADFA65DB0B122CA40E42FA709189B719A4F0D746E2F6069BAF11CEBD650F14B93C977352FD13B1EEA6D6E1DA775502ABFF89D3A8B3615FD0DB49B88A976BC20568489284E181F6F11E270891C8EF80017BAD238E363039A458470F1749101BC29949D3A4F4038D463938851579C7525A69984F15B5667F34209B70EB261136947FA123E549DFFF00601883AFD936FE411E006E4E93D1A00B0FEA541BBFC8C5186CB6220503A94B2413110D640C77EA54BA3220FC8F4CC6CE77151E29B3E06578C478BD1BEBE04589EF9A197F6F806DB8B3ECD826CAD24F5324CCDEC6E8FEAD2C2150068602C8DCDC59402CCAC9424B790048CCDD9327068095EFA010B7F196C74BA8C37B128F9E1411751633F78B7B9E56F71F77A1B4DAAD3FC54B5E7EF935D9A72FB176759765522B4BBC02E314D5C06B64D5054B7B096C601236E6CCF45B5E611C805D335DBAB0C35D226CC208D8CE4736BA39A0354426FAE006C7FE52D5267DCFB9C3884F51FDDFDF4A9794BCFE0E1557113749E6C8EF421DBA263AFF68739CE00ED80FD0022EF92D3488F76DEB62BDEF7BEA6026F22A1D25AA2A92D124414A8021FE0C174B9803E6BB5FAD75E186A946A17280770F1243F4387446CCCEB2222A965CC30B3929

e = 3

res = 0 # res即k

c = int(open('flag.enc', 'rb').read().encode('hex'), 16)

print
time.asctime()

for i in xrange(200000000):

if gmpy2.iroot(c + n * i, 3)[1] == 1:
res = gmpy2.iroot(c + n * i, 3)[0]

print
i, res

print
libnum.n2s(res)

print
time.asctime()

break