My preferred programming language is:
- 🔭 I’m currently working on alibaba.
- 🌱 I’m currently learning Sketch.
License: MIT License
# Season @ MacBook-Pro in ~ [14:36:10] C:1
$ telnet www.baidu.com 80
Trying 115.239.210.27...
Connected to www.a.shifen.com.
Escape character is '^]'.
GET /index.html HTTP/1.1
Host: www.baidu.com
HTTP/1.1 200 OK
Date: Thu, 06 Jul 2017 06:36:51 GMT
Content-Type: text/html
Content-Length: 14613
Last-Modified: Wed, 28 Jun 2017 02:16:00 GMT
Connection: Keep-Alive
Vary: Accept-Encoding
Set-Cookie: BAIDUID=E86BAD5D7B7EE6E180136A952EFE8D92:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=E86BAD5D7B7EE6E180136A952EFE8D92; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1499323011; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
X-UA-Compatible: IE=Edge,chrome=1
Pragma: no-cache
Cache-control: no-cache
Accept-Ranges: bytes
<!DOCTYPE html><!--STATUS OK-->
<html>
...
</html>Connection closed by foreign host.
服务端 CentOS 7
客户端 Ubuntu 16.04
sudo yum install tinyproxy -y
vim 打开 /etc/tinyproxy.conf
文件。
注释所有 Allow 字段,允许所有 IP 访问。
其他操作查看文档注释。
service tinyproxy restart
curl www.baidu.com --proxy x.x.x.x:8888
使用 stunnel 让客户端与服务端通讯加密
# 安装
sudo yum install stunnel -y
# 修改配置文件
cd /etc/stunnel
vim stunnel.conf
# 生成证书
openssl genrsa -out privatekey.pem 2048
openssl req -new -x509 -key privatekey.pem -out publickey.pem -days 3650
cat privatekey.pem publickey.pem >> /etc/stunnel/stunnel.pem
配置信息
client = no
[tinyproxy]
accept = 5000
connect = 127.0.0.1:8888
cert = /etc/stunnel/stunnel.pem
启动 stunnel
vim /usr/lib/systemd/system/stunnel.service
systemctl enable stunnel
systemctl start stunnel
[Unit]
Description=SSL tunnel for network daemons
After=syslog.target
[Service]
ExecStart=/bin/stunnel /etc/stunnel/stunnel.conf
ExecStop=kill -9 $(pgrep stunnel)
ExecStatus=pgrep stunnel
Type=forking
[Install]
WantedBy=multi-user.target
多节点配置
[tinyproxy 0]
client = yes
cert = /etc/stunnel/stunnel0.pem
accept = 9000
connect = 47.89.185.169:5000
[tinyproxy 1]
client = yes
cert = /etc/stunnel/stunnel1.pem
accept = 9001
connect = 47.89.24.206:5000
service 文件配置
[Unit]
Description=SSL tunnel for network daemons
After=syslog.target
[Service]
ExecStart=/usr/bin/stunnel /etc/stunnel/stunnel.conf
ExecStop=kill -9 $(pgrep stunnel)
ExecStatus=pgrep stunnel
Type=forking
[Install]
WantedBy=multi-user.target
sudo systemctl restart stunnel.service
安装好 docker 后,输入命令
docker ps
查看正在运行的 container,更多选项查看 docker ps --help
image 是静态的,由一个文件系统和一堆参数组成。当 image 被启动后,就被加载到 container。
当输入命令
docker run hello-world
Docker 会如下执行:
hello-world
imageimage 可能运行一个简单的命令然后退出,但也可以启动像数据库这般复杂的程序。使用 Docker,你完全不需要关心运行环境,container 会帮你解决这些问题。
Docker 让我们可以创建并且分享 image。就像使用 GitHub 一样,你可以浏览 Docker Hub 找到各种你想要的 image。
类似于上文的 hello world 事例,输入命令
docker run docker/whalesay cowsay boo
此时你就运行了一个 whalesay image,执行过程和 hello world 一样,只不过多了一些参数而已。
当你在 container 中运行 image,Docker 会先将 image 下载到本地,以后再执行此命令,会优先从本地读取。只有hub 上的 image 的发生改变,Docker 才会重新下载。
如果要查看本地已有的所有 image,输入
docker images
首先要知道 Dockerfile
的概念,类似于 node 的 package.json
,Dockerfile
是一个构建 image 的描述文件。
在项目目录下,创建一个 Dockerfile
文件
# FROM 关键字代表基于指定 image 改进,这里我们需要使用 whalesay image 的 cowsay 程序
FROM docker/whalesay:latest
# whalesay image 是基于 Ubuntu,所以我们使用 apt-get 来安装包,fortunes 程序会随机输出名人格言
RUN apt-get -y update && apt-get install -y fortunes
# CMD 命令会在环境设置完毕后执行
CMD /usr/games/fortune -a | cowsay
执行命令构建 image
docker build -t docker-whale-test .
-t 参数会给 image 打个标记,方便以后运行。不要忘记 .
,表示从当前目录寻找 Dockerfile
文件。
此时你就可以运行构建好的 image
docker run docker-whale-test
每次执行都会随机输出一条名言。
docker images
可以看到 docker-whale-test 的 id
确保你有 Docker Hub 的账号,运行:
docker tag ${image id} ${hub accountname}/docker-whale-test:latest
再次执行
docker images
确保 docker-whale-test 已经被打上标签。
在 push image 到 Docker Hub 之前,你需要登录
docker login
在 Docker Hub 站点上创建一个同名仓库,然后执行
docker push ${hub accountname}/docker-whale-test
上传成功后,就可以到仓库首页查看具体信息了。
上传到 Docker Hub 后,你可以在任何地方通过 docker pull
获取 image。
首先你要删除本地的备份,否则 docker pull
会认为本地存在指定 image 而不去 Docker Hub 上获取 image。
通过以下命令删除本地指定 id 的 image
docker rmi -f ${image id}
使用 docker image rm -f
命令可以批量删除
最后执行
docker run ${hub accountname}/docker-whale-test
就会自动下载并运行 image
dex2jar.bat classes.dex
命令,会生成 classes-dex2jar.jar 文件;2.0 版本直接执行 sh d2j-dex2jar.sh -f ~/path/to/apk_to_decompile.apk
,出现权限问题执行 sudo chmod +x d2j_invoke.sh
。通过 USB,让 Mac 直接 ssh 连接 iPhone 设备。
在 Cydia 中搜索并安装 OpenSSH。
brew install libimobiledevice
iproxy 2222 22
ssh -p 2222 [email protected]
root 账户默认密码:alpine
touch ~/Library/LaunchAgents/com.usbmux.iproxy.plist
launchctl load ~/Library/LaunchAgents/com.usbmux.iproxy.plist
com.usbmux.iproxy.plist文件中的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.usbmux.iproxy</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/iproxy</string>
<string>2222</string>
<string>22</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
GET 获取请求链接:https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Fapp%3Ddesktop%26action_handle_signin%3Dtrue%26hl%3Dzh-CN%26next%3D%252F%26feature%3Dsign_in_button&passive=true&hl=zh-CN&service=youtube&uilel=3#identifier
获取 Name 为 GAPS 的 Cookie。
获取 Body 中的 gxf 值:document.querySelector('input[name="gxf"]').value
POST 表单提交到:https://accounts.google.com/signin/challenge/sl/password
带上之前获取到 GAPS Cookie,Body 中需要填写账号密码以及上面获取到 gxf 值。
请求成功后拿到登录到 Cookie,其中比较重要的是 SID 和 SSID。后续点赞,评论等操作务必带上这两个 Cookie。(后续会有一堆 302 重定向,会产生新的 SSID,确保新的 SSID 替换原先的 SSID)
URL: https://www.youtube.com/service_ajax
Method: POST
FormData:
ltct 和 se 参数保存在点赞按钮的 data-post-data 属性中。
document.querySelector('button.like-button-renderer-like-button').attributes['data-post-data'].value
session_token 保存在隐藏的 input 标签中。
document.querySelector('input[name=session_token]').value 或者 全文搜索 XSRF_TOKEN 字段,对应的值就是 session_token,参考正则:const regex = /\'XSRF_TOKEN\':(.*?)\"(.*?)\"/g
URL: https://www.youtube.com/comment_service_ajax?action_create_comment=1
Methond: POST
FormData:
params 为评论按钮 data-params 属性的值。
document.querySelector('button.comment-simplebox-submit').attributes['data-params'].value
bgr: 暂无解决方案,可能不是必填参数,没有实际测试。
session_token 保存在隐藏的 input 标签中。
document.querySelector('input[name=session_token]').value
开启 Charles,打开 Chrome 登录微博,登录成后,抓取所有可能到包。
搜索你的密码,发现并没有任何一个请求有发送微博密码,同时搜索账号信息,没有任何可用的结果。
可以猜想,发送的账号和密码可能被加密了。
此时可以搜索 username
关键字,查找这些字段被加密的地方。此时找到一个 i.sso.sina.com.cn/js/ssologin.js
文件,分析代码可以找到以下几个函数和关键代码:
loginByXMLHttpRequest(username, password, savestate, qrcode_flag)
loginByIframe(username, password, savestate, qrcode_flag)
loginByScript(username, password, savestate, qrcode_flag)
// prelogin 方法下
username = sinaSSOEncoder.base64.encode(urlencode(username))
可以猜想 username
被转成了 bese64
,通过微博账号在控制台输入:
btoa(encodeURIComponent('[email protected]'))
即可得到微博账号的一串 base64
字符串,然后在 Charles 中继续搜索改字符串。
发现在 GET https://login.sina.com.cn/sso/prelogin.php
和 POST https://login.sina.com.cn/sso/login.php
时,分别在 QueryString 和 Form 表单中的 su
字段,带上了这串处理后的字符串。由此可见 su
就是我们的账号。
我们先从 prelogin 入手,我们细心地将相关代码提取出来:
// 调用 prelogin 代码
me.prelogin({
username: username
}, callback)
// objMerge 合并对象 kv
var objMerge = function(obj1, obj2) {
for (var item in obj2) {
obj1[item] = obj2[item]
}
return obj1
};
// 生成 URL,简单点理解就是将对象拼接成 QueryString
var makeURL = function(url, request) {
return url + urlAndChar(url) + httpBuildQuery(request)
};
var urlAndChar = function(url) {
return (/\?/.test(url) ? "&" : "?")
};
var httpBuildQuery = function(obj) {
if (typeof obj != "object") {
return ""
}
var arr = new Array();
for (var key in obj) {
if (typeof obj[key] == "function") {
continue
}
arr.push(key + "=" + urlencode(obj[key]))
}
return arr.join("&")
};
// 插入一段 JS 代码到 script 标签并执行
var excuteScript = function(id, scriptSource, charset) {
removeNode(id);
var head = document.getElementsByTagName("head")[0];
var newScript = document.createElement("script");
newScript.charset = charset || "gb2312";
newScript.id = id;
newScript.type = "text/javascript";
newScript.src = makeURL(scriptSource, {
client: me.getClientType(),
_: (new Date()).getTime()
});
head.appendChild(newScript)
};
// 获取客户端类型,该脚本会固定输出 ssologin.js(v1.4.19)
this.getClientType = function() {
return me.getVersion().split(" ")[0]
};
this.getVersion = function() {
return "ssologin.js(v1.4.19) 2017-01-09"
};
// prelogin 内部逻辑
this.prelogin = function(config, callback) {
var url = ssoPreLoginUrl;
var username = config.username || "";
// base64 处理账号
username = sinaSSOEncoder.base64.encode(urlencode(username));
delete config.username;
var arrQuery = {
entry: me.entry, // 追踪到最后,发现是一个固定的 weibo 值
callback: me.name + ".preloginCallBack", // JSONP 相关的调用方式
su: username, // base64 处理后的 username
rsakt: "mod"
};
// 拼接 URL
url = makeURL(url, objMerge(arrQuery, config));
// JSONP 的回调
me.preloginCallBack = function(result) {
if (result && result.retcode == 0) {
me.setServerTime(result.servertime);
me.nonce = result.nonce;
me.rsaPubkey = result.pubkey;
me.rsakv = result.rsakv;
pcid = result.pcid;
preloginTime = (new Date()).getTime() - preloginTimeStart - (parseInt(result.exectime, 10) || 0)
}
if (typeof callback == "function") {
callback(result)
}
};
preloginTimeStart = (new Date()).getTime();
excuteScript(me.scriptId, url)
};
可以看出 preLogin 主要是带参数请求获得一段 JSON 参数。
QueryString 主要有以下参数:
继续分析请求 login.php 对应着抓包来的 form 表单,分析 ssologin.js 代码,可以知道这个 form 是如何生成的:
# 基本固定参数
entry: 'weibo'
gateway: '1'
from: ''
savestate: '7'
useticket: '1'
pagerefer: ''
vsnf: '1'
su: username
service: 'miniblog'
pwencode: rsa2
sr: 1920*1080
encoding: UTF-8
# preloginTime 随便填一个数字就好了
prelt: 53
# 根据 showpin 参数确认是否输入验证码
door: 验证码
# prelogin 回复的值
nonce: S79EWR
pcid: gz-c1a9643dd132af46aae0a346449b00fc51d1
servertime: 1489033504
rsakv: 1330428213
# 加密后的密码
sp: 2a75606599d7d16eec9cb5a0fd5d37514f83a971ac9c707e08d19873113f42599ed793d48c9acb87e3138df2e8b1f05121db67675c46f13cc55b630c093f1675c45de263946259a3cd6953d683aacccb9b1cd3ce9eebdc533b8b299371fd7c291848cfeb95f3a7dd1accbd81f57a5fd33f1803d3472b451abbb1f9d9915daed2
url: http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack
以下是 password 的加密过程:
var makeRequest = function(username, password, savestate, qrcode_flag) {
...
if ((me.loginType & rsa) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.RSAKey) {
request.servertime = me.servertime;
request.nonce = me.nonce;
request.pwencode = "rsa2";
request.rsakv = me.rsakv;
// 重点就是这里的一段加密过程
var RSAKey = new sinaSSOEncoder.RSAKey();
RSAKey.setPublic(me.rsaPubkey, "10001");
password = RSAKey.encrypt([me.servertime, me.nonce].join("\t") + "\n" + password)
} else {
if ((me.loginType & wsse) && me.servertime && sinaSSOEncoder && sinaSSOEncoder.hex_sha1) {
request.servertime = me.servertime;
request.nonce = me.nonce;
request.pwencode = "wsse";
password = sinaSSOEncoder.hex_sha1("" + sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password)) + me.servertime + me.nonce)
}
}
request.sp = password;
...
};
知道加密过程以及 form 各个参数的填写,那么现在登录请求就很好模拟了。至于验证码的,重点关注下 showpin 这个参数就好了。
POST https://passport.baidu.com/v2/api/?login
Cookie: BAIDUID
curl -i --user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' http://www.baidu.com
GET https://passport.baidu.com/v2/api/
QueryString:
sub_source: "leadsetpwd",
userName: e,
isPhone: t.config.isPhone,
dv: i
图片链接:
https://passport.baidu.com/cgi-bin/genimage?${codestring}
GET https://passport.baidu.com/v2/api/
POST https://passport.baidu.com/v2/getpublickey
POST https://passport.baidu.com/v2/api/?login
function gidGen() {
return "xxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(e) {
var t = 16 * Math.random() | 0,
n = "x" == e ? t : 3 & t | 8;
return n.toString(16)
}).toUpperCase()
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.