• 1. Stay - Post
  • 2. Circles - Post
  • 3. Hollywood's_Bleeding - Post
  • 4. A_Thousand_Bad_Times - Post

My Interview Problems For Practice

无论何种漏洞,其思路都是两个,减小危害,减少攻击。

基础面

python2与python3区别,进行了哪些优化

答:

  1. python2中print是一个语句,而python3中print是一个函数,exec同样,这点可从使用方法上看出
  2. python2中input获得int,raw_input获得string,而python3中input()统一获得string
  3. python使用xrange()提高迭代速度,而python3中统一使用range(),两者方法实现相同
  4. python3中打开文件只能使用open()
  5. python2默认使用ascii码编码,python3中字符串默认是unicode编码储存
  6. python2中字符串有两个类型一个为unicode,一个为str,前者为文本,后者为字节序列,python3做了区分变成了str为文本,byte为字节序列,两者使用.encode,.decode进行转换
  7. Python2中TrueFalse为全局变量可被赋值,Python3中这两者变成了关键词。
  8. Python引入了nonlocal可将一个局部变量声明成非局部变量。

当页面存在大量JS时,如何使用爬虫爬取正确的数据

答:使用selenium等爬虫框架,配合无头浏览器让JS渲染好页面后,再爬取数据

常用的Python库有哪些

答:

  1. 迭代器-itertools
  2. threading-线程库
  3. requests 实现简单的http请求
  4. hashlib库进行加密
  5. pickle库实行pickle反序列化
  6. re库使用正则的时候需要
  7. os库做系统相关的操作时需要使用
  8. sys库可能会用sys.argv.argparse读取命令行参数

Django 和 Flask区别与使用

答:

  1. Django是大而全的框架,自带ORM和模板引擎,代码耦合度高,从框架层面为开发者定制好了很多内容,不自由。
  2. Flask是轻量级的框架,框架本身基本只实现了开启了http服务这个功能,其模板引擎使用jinja进行渲染,由于代码耦合度低,因此自由,能由开发者自行实现需要功能或者使用第三方库实现。

你提到了ORM,能简述一下ORM是什么吗?

答:ORM对象关系映射,就是我们在语言层面创建好数据对应的对象,其中需要包括属性和方法,然后我们将对应的属性和方法映射到数据库内,比如属性对应的就是表名,方法可以定义如何存储。

能简述一下进程,线程和协程的原理和区别吗?

答:

原理:

  1. 进程是一个程序执行的实例,它拥有独立的堆栈,不共享,是CPU进行资源分配的最小单位
  2. 线程是程序的一条执行流,他是cpu能够调度的最小单位,拥有独立栈和共享的堆。
  3. 协程由使用者控制,从语言层面理解可以看作一个个函数就是一个个协程,他们辅助线程完成程序执行的工作。

并行与并发的区别

答:两者都是描述程序多进程的执行。

  1. 对并行而言,其描述的是多个进程同时执行的状态,因此一般程序写下的多线程都是指的并行,这个可有开发者进行控制
  2. 对并发而言,其描述的是快速的进行进程间的切换,从而达成看起来像是多进程执行的假象,这个是由操作系统进行控制的,更准确一点是由系统内核进行调度

线程池与多线程的区别

答:

  1. 线程池是在程序运行时,就创建好挂起,等待任务到来。多线程这是由任务到来时进行创建的
  2. 线程池不会回收线程,多线程在任务执行完成后会收回该线程
  3. 线程池中的建成是提前创建好的,不需要在临时创建线程也不会回收,多线程则是临时创建的,会回收因此多线程相较于线程池效率会比较低。

多线程情况下会出现什么安全问题,如何解决。

答:多线程情况下如果访问某个全局变量,可能会存在竞态的问题,在一个线程还在操作或者读取变量时,另一个线程同时进行读取操作,可能会产生一些未知错误。解决方案主要是使用线程锁,保证每次只会有一个线程操作该变量。

进程之间是如何通讯的

答:以linux为例,主要有

  1. 管道
  2. 信号
  3. 信息队列
  4. 共享内存
  5. 信号量
  6. 套接字(也可用于不同机器间进行通讯)

协议相关

TCP的三次握手和四次挥手

答:

TCP的三次握手:

由客户端发送连接请求,服务端收到请求后返回一个确认该连接请求的信息,然后客户端再发送了一个确认收到的请求给服务器

TCP四次挥手:

由客户端发送请求给服务端,先发送断开请求的信息给服务端,服务端再返回一个确认收到并断开连接的信息给客户端,此时客户端到服务端的连接断开,然后服务端发送一个断开请求的信息给客户端,客户端再返回一个确认收到并断开连接的请求给服务端,此时服务端到客户端的连接也断开了

TCP与UDP的区别

答:

TCP是可靠传输,双向连接,且面向字节流,是一对一的连接。

UDP是不可靠传输,无连接的,且面向报文,可以单播,多播,广播。

http协议常见表头含义以及状态码含义

请求头:

Accept-Charset ——用于指定客户端接受的字符集

Accept-Encoding—— 用于指定可接受的内容编码,如Accept-Encoding:gzip.deflate

Accept-Language—— 用于指定一种自然语言,如Accept-Language:zh-cn

Host ——用于指定被请求资源的Internet主机和端口号,如Host:www.taobao.com

User-Agent ——客户端将他的操作系统、浏览器和其他属性告诉服务器

Connection ——当前连接是否保持,如Connection:Keep-Alive

响应头:

Content-Type ——用来指明发送给接收者的实体正文的媒体类型

常见类型:

  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml : XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式

    以application开头的媒体格式类型:

  • application/xhtml+xml :XHTML格式
  • application/xml : XML数据格式
  • application/atom+xml :Atom XML聚合格式
  • application/json : JSON数据格式
  • application/pdf :pdf格式
  • application/msword : Word文档格式
  • application/octet-stream : 二进制流数据(如常见的文件下载)
  • application/x-www-form-urlencoded :表单提交
  • multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

Content-Encoding ——与请求报头Accept-Encoding对应,告诉浏览器服务端采用的是什么压缩编码

Content-Language ——描述了资源使用的自然语言,与Accept-Language对应

Content-Length ——指明实体正文的长度,用以字节方式存储的十进制数字来表示

Keep-Alive——保持连接的时间,如Keep-Alive:timerout=5,max=120

状态码:

20x请求成功

30x表跳转

40x表示请求有误<400请求语法错误><403服务器禁止该请求><404找不到请求资源>

50x表示服务器错误<500服务器未知错误>

通过网址打开网页时发生了什么?

答:

  1. 查找DNS记录,DNS服务器返回该域名对应的ip
  2. 建立连接后,服务器将请求资源发回
  3. 浏览器进行资源解析,解析完成后绘制网页。

https数字证书交换过程

答:

  1. 客户端向服务器发送加密请求信息
  2. 服务器用自己的私钥加密返回内容后,连同本身的数字证书一起发给客户端
  3. 浏览器根据返回的数字证书,查看解开数字证书的公钥是否在列表中
  4. 如果存在列表中,则使用服务器公钥解密加密的内容

漏洞面

通性漏洞

简要描述CSRF漏洞

跨站请求伪造,即盗用身份,发送恶意请求,攻击者可以生成一个自动提交的恶意表单,让用户登陆获得网站信任(cookie),点击该表单提交,从而实现发送而已请求

修复方法:

  1. 增加csrfToken,验证表单的正确性。
  2. 使用验证码进行表单验证
  3. 校验Referer是否为允许的源
浏览器同源策略是什么,如何实现跨域

答:

浏览器同源策略指同协议,同域名,同端口的网站会被视作同源,不同源则浏览器会对document或脚本的读取和设置进行一定的限制

(<script><link><img><iframe>等可以加载远程资源,相当于发起一次GET请求,但不能进行读和写的操作)

  1. Cookie,LocalStorage,IndexDB无法读取
  2. DOM无法获得(iframe标签)
  3. AJAX请求不能发送。

跨域可以使用一下方法:

  1. JSONP,利用GET方法向服务器请求JSON数据的行为,不受同源策略影响,最后URL加上callback=xx指定需要调用哪个函数即可,兼容性较好支持老版本的浏览器。
  2. WebSocket,该协议不使用同源策略,只要服务器支持就能够使用该协议进行跨域通信
  3. CORS,跨源资源分享,能够使用任何类型的请求方法,CORS请求与AJAX请求相似,但是需要在头信息加上Origin字段表明来源,如果来源在许可范围以内,服务响应头会多出`Acess-Control-Allow,常用于各种前后端分离的web项目中。
  4. 利用windows对象,由于该对象不受同源策略限制,因此可以利用该对象的内置方法进行跨域通信。

简要描述XSS漏洞

XSS为跨站脚本攻击,即在html注入JS恶意代码,从而在用户访问网页时自动执行恶意脚本,达到攻击的目的,如盗取Cookie等操作,由于XSS主要是JS的代码执行,因此JS能做什么,XSS就能实现怎样的攻击。

修复方法:

  1. HttpOnly限制XSS读取Cookie
  2. 对用户输入进行过滤
  3. 对服务端的输出进行校验(使用htmlencode编码)
  4. 使用CSP策略,减少XSS攻击
存储型XSS,反射型XSS,DOM型XSS区别在哪:

答:

  1. 存储型XSS是储存在数据库里的,因此用户每次访问网页都会触发恶意代码,从数据包角度来看,每次请求都会返回XSS恶意代码
  2. 反射型XSS无法进行持久的攻击,通常情况只能触发一次,只能在当前数据包中发现XSS恶意代码
  3. DOM型XSS由于输出点在DOM树中,非常隐蔽,在数据包中无法发现XSS恶意代码,因为恶意代码以及被注入到DOM树中了
CSP相关

答:

特点在协议层面对XSS进行防御,而非单纯的白名单和黑名单过滤,通过CSP能够对加载的资源进行控制,这样就很好的减少了XSS的攻击,使用方法只需要在html协议Header头加入对应内容,或者在html文件里加上对应的标签即可。

简述SSRF漏洞

服务器请求伪造,即通过服务器提供的类似于爬虫或者请求外部资源的服务,进行请求伪造,从而攻击内网其他服务,也可用于探测内网信息,或者穿透防火墙,目前常见利用是SSRF+Redis写入shell。

漏洞点:
  1. 对外发起网络请求
  2. 请求外部资源
  3. 数据库内置功能-导入数据库资源
  4. 邮件系统-接受邮件服务器地址
  5. 文件处理系统-xml或者图片处理
  6. 在线处理工具-在线翻译或者识图等。
修复方法(思路 1. 如何判断是否为内网Ip 2.如何获得用户真实的ip ):
  1. 校验请求是否为内网的IP,由于存在不同进制表示IP地址,因此可将IP地址转化为整数再做校验
  2. 获取请求真正的HOST

    (1)保证解析URL的一致性,不同语言的不同函数可能解析出的结果不同,因此要保证解析结果的一致性,否则就存在绕过的可能。

    (2)多次解析HOST,xip.io域名可能绕过直接的检查,因此可以先获得HOST后解析,然后再次检查是否为内网IP。

相关协议:

http/https,dict,file,gopher,ftp(s)/smb(s),tftp,telnet,ldap,git等。

相关绕过:

  1. 利用解析规则的差异性进行绕过,如php parse_urlcurl的不同
  2. ip转换进制绕过,或者使用xip.io这个特殊域名
  3. 使用简略记法[::]绕过localhost限制

简述SQL注入

答:

原理:

SQL注入原理为数据与代码没有区分开,将用户输入错当作代码一部分,当用户使用与数据库相关功能时,可拼接恶意查询语句,造成一系列的安全问题。(注入类问题实质都是数据与代码没有区分开)

常见手法:

  1. union联合查询(这个实在是太少了,group_concat常用)
  2. 报错注入(常用自带函数,extractvalue,updatexml,rand+floor的主键重复),利用报错时会解析sql语句来进行回显
  3. 盲注(常用自带函数hex,mid,substr,char,benchmark,sleep),一般简单分为布尔盲注和时间盲注。
  4. 堆叠注入,能够执行多条SQL语句。
  5. 宽字节注入,PHP中如果使用addsalshes函数进行过滤,单引号会添加\进行转义,如果mysql支持字符集为GBK,因为汉字是使用两个字节进行表示的,当前者url编码的数大于128,则和同后面的\会被当做中文中的一个字符,这样\被吞掉了,从而将单引号逃逸出来。(实际原理是高位字节的编码和地位字节的编码需要在编码集里)
  6. sql写入shell,一般使用into dump/outflie进行写入,前者是二进制写入,后者为文本写入,Load_file进行读取文件
  7. 或者利用其他关键词进行的注入比如order bylikeinsertupdate等关键词,注意insertupdate,会产生脏数据,因此不推荐使用sqlmap进行自动化注入

常见绕过:

1.特殊方法:

# 
--
-- - //5.6.12特性,需要加空格
--+
//
/**/ //c风格注释
/**//**/  //多个注释
/*letmetest*/
;
# 科学记数法
id=0e1union select
# 空白字符
SQLite3 0A 0D 0C 09 20 
MySQL5 09 0A 0B 0C 0D A0 20 
PosgresSQL 0A 0D 0C 09 20 
Oracle 11g 00 0A 0D 0C 09 20 
MSSQL 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20

2.利用中间件特性或漏洞

3.%0a进行换行

4.进行编码绕过如hex,base64,url等方式

修复方法(sql注入类):

  1. 使用WAF进行校验,对用户输入进行过滤,对用户输入进行长度限制,关闭错误回显,限制用户同一时间请求量。
  2. 使用sql语句预编译,能够很好防护sql注入,但注意预编译只能防范查询参数的拼接,同时也有缓冲区溢出的风险,比如order by或者表名之类的地方无法使用预编译防范sql注入
  3. 做好权限管理,防止从小洞转变为大洞
  4. 对重要数据内容进行加盐哈希加密

题外话:

有关SQL与NoSQL:

两者并无好坏只是应用场景的问题,SQL作为关系型数据库,结构严谨,能够进行复杂的复合查询,扩展性低,高并发和海量数据环境下表现差。而NoSQL非关系数据库,是使用键值对存储,数据间没有关系,有更好的扩展性,性能更好。

简述命令注入

原理:

在数据可控的情况下,使用了语言中能够执行代码的函数,导致攻击者可以执行系统命令。一般需要配合其他漏洞达到命令执行的目的。

常见特征:

  1. 使用高危函数,如eval,system
  2. 动态解析的参数的地方。
  3. 高危函数的参数可控。

修复方法

  1. 对高危函数参数进行过滤和校验
  2. 如果只需要使用某个命令或某个功能,则不使用bashcmd执行
  3. 使用有限制的bash
  4. 将命令放置在沙盒中运行。
  5. 使用更安全的函数代替高危函数的功能

简述文件相关类漏洞

文件上传漏洞

一般上传webshell,配合命令执行,拿下服务器权限,更常用于测试当前服务器环境对哪一类文件具有可执行权限。

一般特征

  1. 能够进行文件上传的功能处
  2. 通常情况下能够猜测或者爆破出保存的路径。
  3. 如果是webshell通常情况下,要保证该路径下能够对上传文件进行执行操作

修复方法:

  1. 限制文件上传目录
  2. 限制上传目录权限
  3. 对用户上传文件类型,进行二进制特征码校验,防止类型绕过。
文件包含漏洞

通常情况下是只存在于php当中的,因为php使用include()require()这种函数将脚本引入,是以函数的形式,而非语句,因此可能存在脚本名可控的情况。同时PHP中的与文件相关的函数支持伪协议和过滤器,在allow_url_fopenallow_url_include开启的情况下,能够大大扩大攻击面。

一般特征

  1. 通常情况下,能够通过某种方式控制包含函数的参数
  2. 文件包含也可以利用../或者./进行目录遍历
  3. 可能会出现在读文件或者写文件的功能块中
  4. 可能会导致PHP反序列化漏洞(phar://伪协议扩大了反序列化漏洞的攻击面)

修复方案

  1. 最好关闭allow_url_fopenallow_url_include防止远程包含
  2. 需要包含的文件使用硬编码的形式写在代码中。
文件遍历

一般是中间件应用配置不当,或者代码有欠缺考虑的地方,导致用户能够使用../或者./进行目录跳转,从而实现目录的遍历。

一般特征

  1. 使用用户输入的参数进行读取对应文件的操作
  2. 直接访问中间件对应的web目录时,由于未配置默认返回界面,会展示整个web目录

修复方案

  1. .././加入黑名单
  2. 对用户需要读取的文件进行统一加密,对部分恶意字符或空字符的文件进行重命名
  3. 配置好相应目录权限。
SSTI注入

(SSTI注入的手法和沙盒逃逸非常类似,都是利用当前环境下的已知变量和方法,达到恶意操作)

SSTI注入就是模板注入,一般会出现在支持模板语言的框架中,因为框架中的内容是动态渲染的,是根据后端传入渲染的前端,因此当用户可控模板内容时,且能够二次渲染的情况下,便会导致模板注入。

特征

  1. 用户可控模板内容
  2. 可控的模板内容能够解析用户输入。

手法

最主要手法流程就是,先测试是否能够动态解析自己的输入返回到页面上,如果能够返回至页面说明模板内容可控,然后是利用模板内本身存在的全局变量,由于模板需要渲染对应的内容,因此必然有变量能够传至模板,利用这些变量和其自带的方法找到一条类似于继承链的东西,非常类似于Java反射等一些列寻找父类的手法。由于这里写在之前,因此先给出图

以Python为例:

一般都是通过一个变量的

__class__方法-->返回该变量所属类

__base(s)__或者__mro__-->获得其父类的元组,区别在于__base__不会包含子类

__subclasses__-->获得该父类的所有应用该父类的子类引用

__init__-->初始化该类,可以理解成加载该类

__global__-->获得该类的全局命名空间的所有变量(返回以模块名和模块组成的键值对的字典)

然后利用字典的操作方法,取得某个模块,最后调用里面的方法执行恶意操作

PS:

Python里面注意getattr()这个非常好用可返回模块的函数。

Flask框架中模板变量当中有request类,其中的args.**号匹配所有的GET请求参数,这样被禁止的关键词可以通过GET请求参数进行引入

简述HTTP协议存在的问题

简述HTTP走私问题

HTTP走私是属于前后组件的对请求包结束的界定不一样的问题,HTTP通常使用两种方式进行包的界定Content-length和分块方式Transfer-Encoding这两种方式,由于CDN和后端对包的结束可能会使用不同方式,因此HTTP走私的攻击方式为CL头和TE头的所有排列组合。

一般特征

  1. 对请求会进行二次处理
  2. 会对会话的内容进行缓存

修复方案

  1. 前后端服务器使用同一套判定规则
  2. 使用HTTP/2协议
  3. 禁止前后端的TCP连接重用
CLRF注入

HTTP数据包通过\r\n\r\n进行headerbody的区分,以\r\n作为行之间的区分,因此可以通过输入\r\n字符串,在校验不严格的Web应用中,实现注入http请求头的操作

修复方案

将空格以外的空白符拉入黑名单,在输入中不允许使用换行符。

语言特性漏洞

PHP反序列化

php以某种具有特定规则的字符串,对对象进行压缩,在利用解析该字符串,从php代码定义中寻找对应的类从而将类还原。但由于PHP作为动态脚本语言,是支持某个属性为一个类,同时PHP序列化字符只保留属性的信息,因此属性值可控。从而导致能够找到一条通过属性和魔术方法,搭建起来的对象链,达到进行恶意操作的目的。

特征

  1. 使用了unserialize方法
  2. 在能够使用伪协议的地方参数可控。

手法

  1. 通过已知类的属性和对应方法,找到一条通过魔术方法搭建起来的链条,看能否执行恶意操作
  2. 通过phar://伪协议上传一个构造好的恶意phar包,由于PHP在处理phar包时,会在源码层面(C)上执行反序列化操作,因此这里不需要unserialize方法来触发反序列化漏洞
  3. 如果对序列化和反序列化字符串进行了字符串增加或者删减的操作,能够利用PHP序列化数据的规则,进行长度逃逸,从而在无法完全控制序列化字符的情况下,能够控制属性进行反序列化攻击。

修复方法

  1. 关闭allow_url_fopenallow_url_include配置
  2. 当触发黑名单后,不使用字符替换的方法进行处理
  3. 不让用户控制反序列化数据,即unserialize方法参数应不可控。

Python反序列化漏洞

实际上说的Python反序列化漏洞是指Pickle反序列化漏洞,Pickle是由Python官方提供的原生序列化和反序列化方法。Pickle的序列化,会将类中的操作抽象层一个堆栈,而通过类中封装的__reduce__方法,能够一定程度操纵这个堆栈,导致命令执行等漏洞。

特征

含有pickle.load()等函数,且这个函数参数可控。

(Numpy 反序列化漏洞就是实际上使用pickle.load()导致的)

手法

本地恶意构造一个含有__reduce__魔术方法的恶意类,将其进行pickle序列化,注意使用序列化协议为0,这样保证不会出现不可见字符,从而不好传入和解析,然后将序列化的数据传入pickle.load()进行反序列化,最后导致pickle反序列化漏洞的触发。

PS:由于类的__reduce__方法只能返回一个元组,因此实际上只能进行一步恶意操作。

修复方法

  1. 使用JSON等方式序列化和反序列化数据
  2. 对传入反序列化数据进行校验。
  3. 使用RestrictedUnpickler类对pickle堆栈语言中的关键词进行检查。

Java反序列化

Java反序列化和PHP反序列化类似都是通过寻找由类组成的链条达到执行恶意操作的目的,区别在于java的序列化数据是字节对象,并且java使用着能够亲自参与序列化和反序列化的过程,自由度更大。与PHP类似,Java反序列化的触发是readObject函数。

特征

实现Serialzation类中的readObject方法,对应的对象可控,且该对象能够找到一条能够执行恶意操作链条。

修复方法

  1. 创建黑名单防止用户输入字节序列中所含的关键字符。
  2. 校验用户输入是否为一个对象
  3. 进行版本更新或者打上补丁。

Java JNDI注入

JNDI注入主要原理是,Java提供一个可以远程调用方法的接口,当lookup()之类的参数可控时,可以由攻击者构造一个恶意的远程对象,让lookup()函数去调用该恶意对象从而实现恶意操作,即RMI。而JNDI结合RMI简单理解便是,通过对远程资源进行命名,然后对命令的资源进行调用,简单来说就是这个用处,当然还有配合其他协议进行JNDI注入的。

特征

  1. 存在lookup()函数,且lookup()参数可控
  2. 允许进行动态协议的转换,如ldap,rmi,iiop等协议
  3. lookup查找对象,返回Reference及其子类的对象类型
  4. 当本地类路径找不到对应类时,会尝试使用URL去寻找。

PS: JNDI注入对JAVA版本非常敏感不同版本会导致payload和利用方法完全不同

修复方法

  1. 关闭动态协议转换
  2. 对输入特殊字符进行转义

Java反射命令执行

Java可以利用反射机制命令执行,所谓反射机制简单理解就是指,能够在运行程序的过程中对类进行操作,而几乎所以面向对象的语言,都需要提供一个从子类寻溯到父类的情况,从而导致能够回溯到java.lang中的类再利用反射机制达成命令执行。

特征

  1. 此处会对用户输入进行解析,最后返回结果
  2. 一般出现的地方和SSTI注入非常类似。

手法

一般步骤都是通过已有类寻找能否回溯到java.lang包中的类,然后使用反射将类加载进来,获得类中的某个方法,最后构造好方法所需的参数,使用invoke进行执行。

相关方法

getclass->获得当前对象类

forName->通过字符串寻找对应名字的类

getMethod->通过名字找方法

invoke->调用并执行当前方法

*ClassLoader->通过不同形式将类加载进行,返回该类。

PS:注意一般情况下,由于使用的命令执行相关类在对含有` ,$一些特殊字符的命令进行解析时,会出现非预期错误,所以需要进行编码对这些命令进行编码解码的操作,从而绕过该错误的产生。

修复方法

  1. 使用黑名单禁止危险关键词和相关类的使用
  2. 使用沙盒环境限制动态解析的可控范围

JavaScript原型污染

在JS当中每一类都会有一个原型,他和父类略有不同,当JS对象被访问一个本类不存在的属性时,会尝试从本类的__proto__中寻找,如果还找不到就会从某个对象.__proto__.__proto__依次向上延伸,直到Object基类为止。而__proto__所代表的类就被称为原型类。而当JS对类进行clone或者递归合并操作时,就很容易发生原型污染,这时候类中含有恶意构造好的__proto__属性(非原型),就会被当作原型合并到新类之中,从而导致该类的原型收到污染。导致创建的任何对象,都会收到恶意属性变成原型的污染。

特征

  1. 对对象进行了合并和克隆操作(含有递归)
  2. 在合并和递归的过程中没有校验__proto__关键词

手法

  1. 寻找是否对对象进行过合并或克隆操作。
  2. 该原型污染的类是否具有恶意操作
  3. 构造好恶意的__proto__属性值,通过合并和克隆操作污染原型
  4. 当该被污染的原型创建对象时,通过组合原型中的属性值结合恶意操作,达到攻击的目的

修复方法

  1. 校验类属性是否含有__proto__属性
  2. 不进行深层合并或克隆操作,也可以和第一条结合控制递归深度。
  3. 粗暴的拉个黑名单

Fastjson回顾

fastjson作为阿里巴巴的开源JSON序列化,反序列化工具,利用json作为对象的压缩和还原。

1.2.24版本链条博客和原理写了,这个就不说了。

补丁对抗史

记住这个早前版本的坑比函数:

  1. 1.2.25版本补丁

    1.2.25 加入了autoTypeSupport作为是否自动加载类的配置项,并且加入了checkautotype函数作为校验,当autoTypeSupport为false时,采用黑白名单进行校验,而使用autoTypeSupport为True时采用黑名单校验。(白名单默认为空)

    我们知道黑名单不是一个好的过滤方法,是存在绕过的可能,绕过只需要在指定加载的类名前加上"L"末尾加上“;”即可绕过,原因是因为TypeUtils.loadClass()加载类的时候,当类名的首字母为"L",末字母为";"时,会将首位的这两个字符去掉,同时这个分支时递归返回,从而导致去掉"L"和";"字符也是递归去除。这就导致了黑名单的绕过了。

  2. 1.2.42版本补丁

    修复方式是利用类Hash的黑名单,将明文比较变成了黑名单的类Hash比较,同时原来的黑名单校验处会去除一次首字母和尾字母,但由于加载类的使用的方法中是递归删除,因此导致这里只需要在加入类名的首字母填上两个及其以上的"L"字母,两个及其以上的";"字母,就能够绕过这个黑名单了。

  3. 1.2.43版本补丁

    将判断方式变成了判断是否为L.....;的方式,如果是则继续判断是否为LL.....;;,从而导致从"L+;"的方式绕过黑名单无望,但可以使用加载类的其他处理函数,比如上图的第二个分支是判断开头的第一个字母是否为"[",如果是则引入对应类,但是最后会返回一个数组类,数组类中的元素就是我们构建的恶意类,同时需要将末尾的字符更改成为“[{”,为","时由于前面加入了"[",导致token匹配不上,查表得此值需要是“[”,但如果改成"[",仍然会报错,这时候跟踪报错信息,发现需要此处的token值不等于"{",也要不等于","

  4. 1.2.45版本补丁

    此时第二处分支会加入直接判断类名是否是"["如果是则会直接抛出一个异常,因此一直存在于黑名单中的com.sun.rowset.JdbcRowSetImpl,不能使用了,通过寻找其他链条成功找到了一个非黑名单里的类为Mybatis包,该包中的jndiDataSourceFactory类中的setProperties方法会得到data_source的值作为lookup的参数,从而又能够利用jndi注入。

  5. 1.2.46-1.2.47版本补丁

    该版本将上面的Mybatis中的类拉入了黑名单,所以该类不能使用了,但利用checkautotype函数的逻辑处理问题和新链条将攻击面大大提升了。

    • autosupport为false时,此处如果传入"java.lang"中的类,会直接返回,然后进入MiscCodec类中进行反序列化处理,此时如果传入了多余的其他属性,则会向下校验从而得到恶意类,然后进行载入并存进缓存,由于此时类被存入了缓存,而当autotype没有开启时,不会进行下面的判断,会直接尝试从缓存中加载该类,从而实现了黑名单和相关参数绕过。
    • 当“autosupport”为true时,前面的部分相同都是把恶意类加入了缓存之中,而当autotype为true时,加载类的时候会判断如果恶意类不在缓存中且黑名单检测到恶意类,则会抛出异常,但这个时候我们的恶意类实在缓存中的,从而绕过此处校验成功加载该恶意类。

长亭实习面试后再学习(亡羊补牢)

Sql方面

哪些数据库能够使用堆叠注入

  • MySQL
  • PostgreSql
  • MSSQL

Oracle并不能

相关连接:SQL注入-堆叠注入

有关benchmark函数的两个参数

当时答的时候记得有两个,只不过答反了,第一个是执行表达式的次数,第二个是需要执行的表达式。

如何进行order by注入

相关链接: MySQL Order By 注入总结

Redis数据库相关问题

你说过了SSRF+Redis未授权能够进行getshell,那么如果是Redis需要授权的情况呢?

这个确实只是知道能,但具体是如何操作的,下文解释的比较详细。

相关连接:

浅析SSRF认证攻击Redis

大概原理是Redis使用的协议为Resp,这个协议在传输数据时,会使用由Bulk String为元素组成的数组,对于字符串foo,由Bulk String编码后为$3\r\nfoo这样的形式(\r\n就是CRLF),那么具体传输的这个数组形式是这样的:

*1(\r\n)
$8(\r\n)
flushall
*3(\r\n)
$3(\r\n)
set(\r\n后面也一样)
$1
x
$28
<?php eval($_GET["key"]); ?>(\r\n)
....

形式类似于*后接数字表示元素个数,$后接数字表示元素字符个数,如果Redis是经过了认证那么认证时的数据类似于这种:

*2
$4
AUTH
$6
123456(此处是redis认证的密码)
*1
$8
flushall

也就是说在需要认证的情景,我们需要以上述形式进行数据传输,并且redis文档中写了该协议支持再单次写入操作发送多个命令,由此需要授权的Redis仍然能够实现攻击。

攻击Redis常用的协议有哪些

当时答的时候只能想起来httpGopher,之前复现网鼎杯CTF题的时候,那里使用的是AJAX请求达成的攻击SSRF,但我知道gopher也可以,Gopher是能够使用Get和Post请求的,但这里针对的面是SSRF,如果已经能够使用到Redis了,实际上还可以使用写入ssh密钥,从而使用SSH协议,

相关连接: 浅析Redis中SSRF的利用

Java方面

Java反序列化数据的TCP特征有哪些

(1)TCP:必有\xac\xed\x00\x05,这个16进制流基本上也意味者java反序列化的开始,当时只记起来了\xac\xed.

(2)HTTP:必有rO0AB,此处为aced0005的base64编码形式。

FastJson在构造Payload式如何绕过WAF

场景是WAF基于关键词封禁,这里因为想的是一般绕过WAF的方法,所以

  1. 对数据进行base64编码,二次url编码等,让WAF无法识别出恶意数据
  2. 添加空白符,问道具体哪些空白符时,人傻了,确实没自己测过

相关链接:

浅析JSON参数解析对WAF的影响

目测PHP的解析规则和FastJson,应该是类似的。

说说Spring和Weblogic的理解吧

Spring框架设计理念和设计模式

从防护角度看Weblogic反序列化历史漏洞

Springboot实际上是Spring框架的扩展,它提供一种更简单的配置方式,配置Spring应用,github上有大佬总结的非常详细了。

Spring Boot Vulnerability Exploit CheckList

总体下来其实大概有三个接口很重要:

/actuator,/env,/jolokia 可能是/actuator接口配后两者的组合

Spring boot1.x以根路由开始,Spring boot 2.x/actuator接口开始

信息泄露(通常使用GET请求,POST一般用于利用漏洞):

  1. /env接口会暴露很多和环境配置有关信息,但密码等关键信息会被*号替代
  2. /jolokia/list,暴露相关的Mbean列表。
  3. /dump,显示线程转储
  4. /trace,显示最后几个HTTP请求,可能存在可利用的Cookie
  5. /logfile,输出日志文件的内容
  6. /mappings,显示MVCController映射

RCE利用:

  1. Spel表达式注入,非常类似于SSTI
  2. Spring cloud SnakeYAML RCE,

    手法:利用/env设置对应系统变量后,使用/refresh接口刷新配置,再利用自己搭建的恶意服务器,利用yml指定远程加载恶意类,从而实现命令执行。

    原理:

    1. spring.cloud.bootstrap.location 属性被设置为外部恶意 yml 文件 URL 地址
    2. refresh 触发目标机器请求远程 HTTP 服务器上的 yml 文件,获得其内容
    3. SnakeYAML 由于存在反序列化漏洞,所以解析恶意 yml 内容时会完成指定的动作
    4. 先是触发 java.net.URL 去拉取远程 HTTP 服务器上的恶意 jar 文件
    5. 然后是寻找 jar 文件中实现 javax.script.ScriptEngineFactory 接口的类并实例化
    6. 实例化类时执行恶意代码,造成 RCE 漏洞
  3. Jolokia-JNDI-RCE

    手法:访问/jolokia/list存在logbackreloadByURL等关键字,全名(ch.qos.logback.classic.jmx.JMXConfigurator),在自己服务器上构造恶意含有<insertFromJNDI>标签的xml文件(这里设置好LDAP协议对应类)和编译好的JavaClass,本机开启LDAP服务利用LDAP协议进行JNDI注入,最终达成RCE

    原理:

    1. 直接访问可触发漏洞的 URL,相当于通过 jolokia 调用 ch.qos.logback.classic.jmx.JMXConfigurator 类的 reloadByURL 方法
    2. 目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容
    3. 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞)
    4. xml 文件中利用 logback 依赖的 insertFormJNDI 标签,设置了外部 JNDI 服务器地址
    5. 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞

(未完待补)

JNDI注入中各协议之间的区别(RMI,LDAP,IIOP)

相关链接:

JNDI注入原理及利用

CVE-2020-2551: Weblogic IIOP反序列化漏洞分析

Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上)

有关 JAVA RMI

引言

RMI为远程方法调用的缩写,由于Java是使用虚拟机机制实现全平台运行,因此当不同Java程序进行时,就涉及到了不同JVM之间的通信,Java中的一个基础元素是类,因此不同JVM的通信自然涉及到如何传递类的问题,其中一个解决问题的机制便为RMIRMI的传输基于JAVA序列化和反序列化机制。

stub和Skeleton

即存根和骨架,存根是本地的一些代码,作为请求远程对象的本地代理,而骨架是指真实的存放在远程主机上的类原型。实际上在进行通信时,传递的是Stub存根,而不是直接复制一个对象,本机使用stub就像使用类本身一样,对于客户机来说Stub类似于远程类的引用或者代理。同时stub里面包含了远程对象的定位信息,如端口,主机地址等等内容。

RMI执行过程
  1. 服务器监听某个供RMI使用的端口,这个端口是JVM随机选择。
  2. 客户端虽然不知道远程对象具体的通信地址和端口,但stub含有这些信息,并将其封装到了底层网络包中
  3. 客户端调用Stub的某个方法,此时Stub连接到对应的远程端口,并提交相应的参数。
  4. 服务端根据Stub提交的参数,执行相应方法后,返回结果给stub,最终Stub返回结果给客户端

然而此时仍然存在一个问题,stub需要调用某个远程服务的方法获得,但想要调用远程方法又必须拥有stub,为了解决这个问题,引入了RMIRegistry,即RMI注册表来解决这个问题,该服务默认监听1099端口,具体过程如下:

正如前面所说RMI通信是基于反序列化和序列化操作的,同时任意以类作为方法参数的RMI接口,都可以接受一个客户端自行构造的类,使服务端通过自身JAVA_ClassPath变量,去寻找可反序列化的类,进行对象的还原。

RMI的动态加载

构建一种情景,当客户端构造出服务端没有的类作为stub参数时,这时候服务端本地的classpath找不到,就会引入java.rmi.server.codebase属性(可依托http,ftp,file等协议),该属性定义了可以从哪个位置或者地方,加载进本地没有的类。这里分为了两个情景:

  1. 调用远程方法后,得到的返回值是客户端没有的类实例,此时客户端会尝试使用服务端的codebase去下载对应的包。
  2. 调用远程方法的参数,是服务器本地classpath没有的类实例,此时服务端会尝试使用客户端提供的codebase下载对应包。

RMI的动态加载存在一定的限制:

  1. 需要配置java.security.prolicy
  2. 需要java.rmi.server.useCodebaseOnly为false
攻击方法
  1. 通过传入恶意构造好的,服务端有的恶意类,作为参数传入给Stub,这个时候RMI会帮我们寻找本地存在的对应类,进行反序列化操作,从而能够触发Java反序列化漏洞
  2. 通过构造某种客户端或服务器上不存在的类,利用Codebase加载远程恶意类,达到攻击的目的。

(未完待补)

手法和漏洞问题

忘记密码处的逻辑问题

相关链接: 逻辑漏洞之密码重置

  1. 利用社工库,一般提供两种重置密码的方式,(1)使用邮件收发验证码,(2)使用密保问题
  2. 生成验证码发送邮件时,一般会生成用户专用的重置密码链接,如果该链接可预测,则不需要控制密保邮箱(比如阿里云之前的重置链接,是以用户id为参数的)
  3. 没有设置验证码的校验次数,导致验证码可爆破,一般验证码都是4位以上的数字组合,如果没有进行校验次数,则可造成验证码可爆破。
  4. 可设置验证码的接受账户,可能在对后端进行包传递时,会传输接受验证码的账户,且没有和服务器的设置账号进行校验,则会导致校验邮箱可控。
  5. 成功得到验证码后没有校验修改密码的用户,如果该修改密码的用户ID可控,则会导致修改其他用户的密码
  6. 过于相信回传包,可抓重置失败后的回传数据包,添加校验成功参数,从而导致验证码校验被绕过。
  7. 重置的新密码,出现在回传包中,可能造成信息泄露。或者重置验证码,是由前端生成传递给服务器,导致通过抓包能够得到验证码,从而导致验证无效。

支付漏洞如何挖掘的问题

相关链接:

挖洞技巧:支付漏洞之总结

支付漏洞乌云案例

  1. 逻辑问题:

    (1)

    在支付订单式会将订单打包成数据包,此时进行抓包的时候,预支付金额和实际支付金额可能会存在偏差,比如预支付到账的金额是进行了加密,但支付金额没有是用户可控的,此时修改实际支付金额,可能导致以小搏大的情况。

    (2)

    购买商品的订单处可能存在商品数量修改的逻辑问题,在用户提交订单的时候,可能会将商品价格等参数一并提交,此时如果商品价格的参数可控,则可以导致使用任意价格购买商品的问题

    (3)

    在商品支付成功后的信息回传可能出现问题,创建两个订单,生成两个订单号,将便宜的订单支付成功之后,抓银行回传包,将订单号替换,从而实现以小买大的情况,即过于相信用户回传包。

    (4)

    如果商品价格等地方出现校验,那么是否其他费用方面没有进行校验,比如运费或者其他费用是否有和服务器校验对应值。

    (5)

    如果对充值的操作会生成相应的订单号,那么是否存在可控订单号的情况,从而造成构造已充值成功的订单号,达成免费充值的操作。

  2. 数值问题

    (1) 是否能够输入负数,可能存在没有校验输入数值是否为负数的情况。

    (2) 验证输入金额数值最大值的问题,由于很多语言是封装了C语言,因此可能会出现int型,在21亿左右的情况下,溢出为0的情况。

  3. 竞态问题

    可能存在使用并发环境进行提现操作时,产生竞态造成结果不符合预期的情况。

安恒面试后学习

支付过程中提交订单相关问题

思路二(注入或横向越权问题):

这个非常感谢面试官帮菜鸡我打开思路,出了支付凭证或者式支付价格之类的问题外,还可以从表单的角度下手,由于用户需要查询表单,这里就引出了查询操作了,然后查询表单的时候必有对应的检索量,那个这里我们可以考虑是否可以修改表单内容,这里就能够涉及到了两次注入了,然后诸如订单号之类的索引,在查询的时候可能存在横向越权行为,修改订单号之后是否能够查询别人的订单之类的内容。

中间件漏洞

这个当时脑子一热直接说没怎么了解,其实想apachenginx,weblogic,Jboss,IIS等均输入中间件,说起中间件那么第一个想起的就应该是和php有关的解析漏洞了,比如apache在配置时,会打开自动修复路径,即当遭遇错误文件格式时,会尝试修复文件格式。又或者常见的weblogic的反序列化漏洞等等,这些均属于中间件漏洞。

相关链接:Web中间件常见漏洞总结


除非注明,ebounce文章均为原创,转载请以链接形式标明本文地址

本文地址:http://ebounce.cn/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/69.html

新评论

captcha
请输入验证码