admin管理员组

文章数量:1516870

最近拼多多客服软件暴露一个极端批量登陆功能,不需要账户密码登陆,不需要扫码,其实技术原理很简单。

原理:通过微信接口获取店铺列表,然后通过店铺ID获取微信的Token,直接将微信Token注入cefsharp即可实现登陆。

使用到的组件:

1.cefsharp,谷歌浏览器开源组件

2.Titanium数据包分析组件

实现方法:

1.先构建数据包拦截类,数据包拦截类官方示例稍微改动一下即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
namespace PddService.FiddlerEx
{
  public  class NetFiddler
    {
        Action<int,string> LogAction { get; set; }
        Action<string> DebugLog { get; set; }
        public NetFiddler(Action<int, string> _LogAction, Action< string> _DebugLog)
        {
            LogAction = _LogAction;
            DebugLog = _DebugLog;
        }
        public  ProxyServer  proxyServer = new ProxyServer();
        public void StartRun(Action<int,string> _runCallBack)
        {
            try
            {
                
                proxyServer.BeforeRequest += OnRequest;
                proxyServer.BeforeResponse += OnResponse;
                //proxyServer.CertificateManager.TrustRootCertificate(true);
                //proxyServer.CertificateManager.CertificateEngine = Titanium.Web.Proxy.Network.CertificateEngine.DefaultWindows;
                //proxyServer.CertificateManager.EnsureRootCertificate();
                proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
                proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
                var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8036, true)
                {
                    // Use self-issued generic certificate on all https requests
                    // Optimizes performance by not creating a certificate for each https-enabled domain
                    // Useful when certificate trust is not required by proxy clients
                    //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
                };
                //explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
                proxyServer.AddEndPoint(explicitEndPoint);
                proxyServer.Start();
                
                //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
                //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
                foreach (var endPoint in proxyServer.ProxyEndPoints)
                    Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
                        endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
                // Only explicit proxies can be set as system proxy!
                proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
                proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
                // wait here (You can use something else as a wait function, I am using this as a demo)
                // Unsubscribe & Quit
                // explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect;
                _runCallBack(0,"ok");
            }
            catch(Exception ex)
            {
                DebugLog(ex.StackTrace);
                _runCallBack(-1,ex.Message);
            }
           
            //proxyServer.CertificateManager.TrustRootCertificate();
            
           
        }
        public void StopRun()
        {
            if(proxyServer.ProxyRunning)
            {
                proxyServer.BeforeRequest -= OnRequest;
                proxyServer.BeforeResponse -= OnResponse;
                proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
                proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
                proxyServer.DisableAllSystemProxies();
                proxyServer.Stop();
            }
        }
        private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
        {
            string hostname = e.HttpClient.Request.RequestUri.Host;
            if (hostname.Contains("dropbox.com"))
            {
                // Exclude Https addresses you don't want to proxy
                // Useful for clients that use certificate pinning
                // for example dropbox.com
                e.DecryptSsl = false;
            }
        }
        public async Task OnRequest(object sender, SessionEventArgs e)
        {
            Console.WriteLine(e.HttpClient.Request.Url);
            DebugLog(e.HttpClient.Request.Url);
            // read request headers
            var requestHeaders = e.HttpClient.Request.Headers;
            var method = e.HttpClient.Request.Method.ToUpper();
            if ((method == "POST" || method == "PUT" || method == "PATCH"))
            {
               
                // Get/Set request body bytes
                byte[] bodyBytes = await e.GetRequestBody();
                e.SetRequestBody(bodyBytes);
                // Get/Set request body as string
                string bodyString = await e.GetRequestBodyAsString();
                e.SetRequestBodyString(bodyString);
                // store request 
                // so that you can find it from response handler 
                string url = e.HttpClient.Request.RequestUriString;
                e.UserData = e.HttpClient.Request;
                if (e.HttpClient.Request.RequestUri.AbsoluteUri.StartsWith(""))
                {
                    LogAction(0,bodyString);
                    string ok = "";
                }
            }
            // To cancel a request with a custom HTML content
            // Filter URL
            if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("google.com"))
            {
                e.Ok("<!DOCTYPE html>" +
                    "<html><body><h1>" +
                    "Website Blocked" +
                    "</h1>" +
                    "<p>Blocked by titanium web proxy.</p>" +
                    "</body>" +
                    "</html>");
            }
            // Redirect example
            if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
            {
                e.Redirect("");
            }
        }
        // Modify response
        public async Task OnResponse(object sender, SessionEventArgs e)
        {
            // read response headers
            var responseHeaders = e.HttpClient.Response.Headers;
            DebugLog(e.HttpClient.Request.Url);
            //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
            if (e.HttpClient.Request.Method == "GET" || e.HttpClient.Request.Method == "POST")
            {
                string url = e.HttpClient.Request.RequestUriString;
                if (e.HttpClient.Response.StatusCode == 200 && e.HttpClient.Request.RequestUri.AbsoluteUri.StartsWith(""))
                {
                    byte[] bodyBytes = await e.GetResponseBody();
                    e.SetResponseBody(bodyBytes);
                    string body = await e.GetResponseBodyAsString();
                    e.SetResponseBodyString(body);
                    LogAction(1, body);
                }
            }
            if (e.UserData != null)
            {
                // access request from UserData property where we stored it in RequestHandler
                var request = (Request)e.UserData;
            }
        }
        // Allows overriding default certificate validation logic
        public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
        {
            // set IsValid to true/false based on Certificate Errors
            if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                e.IsValid = true;
            return Task.CompletedTask;
        }
        // Allows overriding default client certificate selection logic during mutual authentication
        public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
        {
            // set e.clientCertificate to override
            return Task.CompletedTask;
        }
    }

OnRequest:

这个是获取微信票据wechatToken,这个票据在后续获取每个店铺微信Token需要到

OnResponse:这个是拦截服务器返回数据,其实就是返回的店铺信息列表,里面包括店铺的userID,userName登陆信息。

获取微信店铺列表的地址是

2.通过wechatToken和店铺的userID获取wxToken,用post就能获取了。

传递userID和wxToken即可获取

public Result WxPost(int userID, string wxToken)
        {
            lock (obj)
            {
                var postDataStr = new {
                    userId=userID,
                    wechatToken=wxToken,
                    smsCode=""
                };
                Result ret = new Result() { PostResult = null, PostState = false };
                string url = "";
                HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(url));
                webReq.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                SafeLink(webReq, url);
                webReq.Method = "POST";
                webReq.Accept = "application/json";
                webReq.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat";
                webReq.ContentType = "application/json";
                webReq.Referer = "";
                webReq.Headers.Add("accept-encoding", "gzip, deflate, br");
                webReq.MaximumAutomaticRedirections = 1;
                webReq.AllowAutoRedirect = true;
                try
                {
                    string postData = Newtonsoft.Json.JsonConvert.SerializeObject(postDataStr);
                    byte[] buf = Encoding.UTF8.GetBytes(postData);
                    byte[] byteArray = System.Text.Encoding.Default.GetBytes(postData);
                    Stream newStream = webReq.GetRequestStream();
                    newStream.Write(buf, 0, buf.Length);
                    newStream.Close();
                    HttpWebResponse myResponse = (HttpWebResponse)webReq.GetResponse();
                    using (StreamReader sr = new StreamReader(myResponse.GetResponseStream(), Encoding.GetEncoding("utf-8")))
                    {
                        ret.PostResult = sr.ReadToEnd();
                        sr.Close();
                        myResponse.Close();
                        ret.PostState = true;
                    }
                }
                catch (Exception ex)
                {
                   
                }
                return ret;
            }
        }

操作步骤:

1.运行程序,启动Titanium代理

2.运行微信电脑版本,点击小程序,打开拼多多商家版

3.点击【店铺管理】

4.点击【切换账户】

到这里,店铺列表和wechatToken都能被取到了,接下来就是如何循环读取微信Token啦。

本文标签: 点击店铺列表获取微信