点击上方蓝字 关注我吧
关于HTTP Client
1.1 相关依赖
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
关于HTTP Client
2.1 HttpClient3
public class GetMethod extends HttpMethodBase
{
public GetMethod(String uri)
{
super(uri);
LOG.trace("enter GetMethod(String)");
setFollowRedirects(true);
}
}
主要通过自实现的 URI 类进行解析:
-
org/apache/commons/httpclient/HttpMethodBase.class
public HttpMethodBase(String uri) throws IllegalArgumentException, IllegalStateException
{
try
{
if ((uri == null) || (uri.equals(""))) {
uri = "/";
}
String charset = getParams().getUriCharset();
setURI(new URI(uri, true, charset));
}
catch (URIException e)
{
throw new IllegalArgumentException("Invalid uri '" + uri + "': " + e.getMessage());
}
}
protected void parseUriReference(String original, boolean escaped) throws URIException
{
if (original == null) {
throw new URIException("URI-Reference required");
}
String tmp = original.trim();
int length = tmp.length();
if (length > 0)
{
char[] firstDelimiter = { tmp.charAt(0) };
if ((validate(firstDelimiter, delims)) &&
(length >= 2))
{
char[] lastDelimiter = { tmp.charAt(length - 1) };
if (validate(lastDelimiter, delims))
{
tmp = tmp.substring(1, length - 1);
length -= 2;
}
}
}
int from = 0;
boolean isStartedFromPath = false;
int atColon = tmp.indexOf(':');
int atSlash = tmp.indexOf('/');
if (((atColon <= 0) && (!tmp.startsWith("//"))) || ((atSlash >= 0) && (atSlash < atColon))) {
isStartedFromPath = true;
}
int at = indexFirstOf(tmp, isStartedFromPath ? "/?#" : ":/?#", from);
if (at == -1) {
at = 0;
}
if ((at > 0) && (at < length) && (tmp.charAt(at) == ':'))
{
char[] target = tmp.substring(0, at).toLowerCase().toCharArray();
if (validate(target, scheme)) {
this._scheme = target;
} else {
throw new URIException("incorrect scheme");
}
at++;from = at;
}
this._is_net_path = (this._is_abs_path = this._is_rel_path = this._is_hier_part = 0);
if ((0 <= at) && (at < length) && (tmp.charAt(at) == '/'))
{
this._is_hier_part = true;
if ((at + 2 < length) && (tmp.charAt(at + 1) == '/') && (!isStartedFromPath))
{
int next = indexFirstOf(tmp, "/?#", at + 2);
if (next == -1) {
next = tmp.substring(at + 2).length() == 0 ? at + 2 : tmp.length();
}
parseAuthority(tmp.substring(at + 2, next), escaped);
from = at = next;
this._is_net_path = true;
}
if (from == at) {
this._is_abs_path = true;
}
}
if (from < length)
{
int next = indexFirstOf(tmp, "?#", from);
if (next == -1) {
next = tmp.length();
}
if (!this._is_abs_path) {
if (((!escaped) && (prevalidate(tmp.substring(from, next), disallowed_rel_path))) || ((escaped) && (validate(tmp.substring(from, next).toCharArray(), rel_path)))) {
this._is_rel_path = true;
} else if (((!escaped) && (prevalidate(tmp.substring(from, next), disallowed_opaque_part))) || ((escaped) && (validate(tmp.substring(from, next).toCharArray(), opaque_part)))) {
this._is_opaque_part = true;
} else {
this._path = null;
}
}
String s = tmp.substring(from, next);
if (escaped) {
setRawPath(s.toCharArray());
} else {
setPath(s);
}
at = next;
}
String charset = getProtocolCharset();
if ((0 <= at) && (at + 1 < length) && (tmp.charAt(at) == '?'))
{
int next = tmp.indexOf('#', at + 1);
if (next == -1) {
next = tmp.length();
}
if (escaped)
{
this._query = tmp.substring(at + 1, next).toCharArray();
if (!validate(this._query, uric)) {
throw new URIException("Invalid query");
}
}
else
{
this._query = encode(tmp.substring(at + 1, next), allowed_query, charset);
}
at = next;
}
if ((0 <= at) && (at + 1 <= length) && (tmp.charAt(at) == '#')) {
if (at + 1 == length) {
this._fragment = "".toCharArray();
} else {
this._fragment = (escaped ? tmp.substring(at + 1).toCharArray() : encode(tmp.substring(at + 1), allowed_fragment, charset));
}
}
setURI();
}
if ((0 <= at) && (at + 1 < length) && (tmp.charAt(at) == '?'))
{
int next = tmp.indexOf('#', at + 1);
if (next == -1) {
next = tmp.length();
}
if (escaped)
{
this._query = tmp.substring(at + 1, next).toCharArray();
if (!validate(this._query, uric)) {
throw new URIException("Invalid query");
}
}
else
{
this._query = encode(tmp.substring(at + 1, next), allowed_query, charset);
}
at = next;
protected void setURI()
{
StringBuffer buf = new StringBuffer();
if (this._scheme != null)
{
buf.append(this._scheme);
buf.append(':');
}
if (this._is_net_path)
{
buf.append("//");
if (this._authority != null) {
buf.append(this._authority);
}
}
if ((this._opaque != null) && (this._is_opaque_part)) {
buf.append(this._opaque);
} else if (this._path != null) {
if (this._path.length != 0) {
buf.append(this._path);
}
}
if (this._query != null)
{
buf.append('?');
buf.append(this._query);
}
this._uri = buf.toString().toCharArray();
this.hash = 0;
}
public void setURI(URI uri) throws URIException
{
if (uri.isAbsoluteURI()) {
this.httphost = new HttpHost(uri);
}
setPath(uri.getPath() == null ? "/" : uri.getEscapedPath());
setQueryString(uri.getEscapedQuery());
}
public HttpHost(URI uri) throws URIException
{
this(uri.getHost(), uri.getPort(), Protocol.getProtocol(uri.getScheme()));
}
public String getHost() throws URIException
{
if (this._host != null) {
return decode(this._host, getProtocolCharset());
}
return null;
}
public int executeMethod(HostConfiguration hostconfig, HttpMethod method, HttpState state) throws IOException, HttpException
{
LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod,HttpState)");
if (method == null) {
throw new IllegalArgumentException("HttpMethod parameter may not be null");
}
HostConfiguration defaulthostconfig = getHostConfiguration();
if (hostconfig == null) {
hostconfig = defaulthostconfig;
}
URI uri = method.getURI();
if ((hostconfig == defaulthostconfig) || (uri.isAbsoluteURI()))
{
hostconfig = (HostConfiguration)hostconfig.clone();
if (uri.isAbsoluteURI()) {
hostconfig.setHost(uri);
}
}
HttpMethodDirector methodDirector = new HttpMethodDirector(getHttpConnectionManager(), hostconfig, this.params, state == null ? getState() : state);
methodDirector.executeMethod(method);
return method.getStatusCode();
}
public URI getURI() throws URIException
{
StringBuffer buffer = new StringBuffer();
if (this.httphost != null)
{
buffer.append(this.httphost.getProtocol().getScheme());
buffer.append("://");
buffer.append(this.httphost.getHostName());
int port = this.httphost.getPort();
if ((port != -1) && (port != this.httphost.getProtocol().getDefaultPort()))
{
buffer.append(":");
buffer.append(port);
}
}
buffer.append(this.path);
if (this.queryString != null)
{
buffer.append('?');
buffer.append(this.queryString);
}
String charset = getParams().getUriCharset();
return new URI(buffer.toString(), true, charset);
}
www.evil.com
。2.2 HttpClient4(<=4.5.12版本)
public String get(String url)
{
String result = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
try {
response = httpClient.execute(get);
-
org/apache/http/client/utils/URIUtils.class
public static HttpHost extractHost(URI uri)
{
if (uri == null) {
return null;
}
HttpHost target = null;
if (uri.isAbsolute())
{
int port = uri.getPort();
String host = uri.getHost();
if (host == null)
{
host = uri.getAuthority();
......
}
return target;
}
authority
的子集,authority
可以包含端口,而host
不含端口。那么如果对应的URL携带的port不规范时,则会抛出对应的异常,例如http://www.evil.com:80.www.sec-in.com
,可以利用一点来调度到httpclient的uri.getAuthority()::
做拆分,一直获取相关的整数,直到为非数字为止:int at = host.indexOf('@');
if (at >= 0) {
if (host.length() > at + 1) {
host = host.substring(at + 1);
} else {
host = null;
}
}
if (host != null)
{
int colon = host.indexOf(':');
if (colon >= 0)
{
int pos = colon + 1;
int len = 0;
for (int i = pos; i < host.length(); i++)
{
if (!Character.isDigit(host.charAt(i))) {
break;
}
len++;
}
if (len > 0) {
try
{
port = Integer.parseInt(host.substring(pos, pos + len));
}
catch (NumberFormatException ex) {}
}
host = host.substring(0, colon);
}
}
:
进行substring切割: host = host.substring(0, colon);
:
来实现:public static HttpHost extractHost(URI uri)
{
if (uri == null) {
return null;
}
if (uri.isAbsolute())
{
if (uri.getHost() == null)
{
if (uri.getAuthority() == null) {
break label155;
}
String content = uri.getAuthority();
int at = content.indexOf('@');
if (at != -1) {
content = content.substring(at + 1);
}
String scheme = uri.getScheme();
at = content.indexOf(":");
int port;
String hostname;
if (at != -1)
{
String hostname = content.substring(0, at);
try
{
String portText = content.substring(at + 1);
port = !TextUtils.isEmpty(portText) ? Integer.parseInt(portText) : -1;
}
catch (NumberFormatException ex)
{
return null;
}
}
else
{
hostname = content;
port = -1;
}
try
{
return new HttpHost(hostname, port, scheme);
}
catch (IllegalArgumentException ex)
{
return null;
}
}
return new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
}
label155:
return null;
}
其他
原文始发于微信公众号(SecIN技术平台):原创 | 浅谈httpClient组件与ssrf
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论