个性化阅读
专注于IT技术分析

逆向工程软件专用API的教程:破解你的Couch

本文概述

旅行是我的爱好, 我是Couchsurfing的忠实粉丝。 Couchsurfing是一个全球旅行者社区, 在这里你可以找到一个住宿的地方或与其他旅行者分享自己的房屋。最重要的是, Couchsurfing帮助你在与当地人互动时享受真正的旅行体验。我参与Couchsurfing社区已有3年多的时间。我最初参加聚会, 然后终于可以接待人。这是多么了不起的旅程!我结识了来自世界各地的许多不可思议的人, 结识了许多朋友。整个经历真正改变了我的生活。

我本人接待了很多旅行者, 远远超过了我实际冲浪的人数。在法国里维埃拉的主要旅游目的地之一居住期间, 我收到了大量的Couch需求(旺季每天最多10个Couch需求)。作为一名自由后端开发人员, 我立即注意到, ouchsurfing.com网站存在的问题是, 它无法真正正确处理此类”高负荷”案例。没有有关你的Couch是否可用的信息-当你收到新的Couch请求时, 你将无法确定你当时是否已经在接待别人。应该以视觉方式显示你接受和未决的请求, 以便你可以更好地管理它们。另外, 如果你可以公开Couch的可用性, 则可以避免不必要的Couch请求。为了更好地了解我的想法, 请查看Airbnb日历。

许多公司因不听用户而臭名昭著。了解了Couchsurfing的历史, 我无法指望他们很快就能实现此功能。自该网站成为营利性公司以来, 社区不断恶化。为了更好地理解我在说什么, 我建议阅读以下两篇文章:

  • http://www.nithincoca.com/2013/03/27/the-rise-and-fall-of-couchsurfing/
  • http://mechanicalbrain.wordpress.com/2013/03/04/couchsurfing-a-sad-end-to-a-great-idea/

我知道很多社区成员都会很高兴拥有此功能。因此, 我决定制作一个应用程序来解决此问题。事实证明, 没有可用的公共Couchsurfing API。这是我从其支持团队收到的回复:

“不幸的是, 我们必须通知你, 我们的API实际上并未公开, 并且目前还没有计划将其公开。”

闯入我的Couch

是时候使用我最喜欢的一些软件逆向工程技术闯入Couchsurfing.com了。我假设他们的移动应用程序必须使用某种API来查询后端。因此, 我不得不拦截来自移动应用程序到后端的HTTP请求。为此, 我在局域网中设置了代理, 并将iPhone连接到它以拦截HTTP请求。这样, 我就能找到他们专用API的访问点, 并找出他们的JSON有效负载格式。

最后, 我创建了一个网站, 该网站的目的是帮助人们管理他们的Couch需求, 并向冲浪者展示Couch的可用日历。我在社区论坛上发布了指向该网站的链接(我认为细分也相当多, 很难在那儿找到信息)。尽管有些人不喜欢该网站要求长Couch床.com凭据的想法, 但这实际上是一个信任问题。

该网站的工作方式是这样的:你使用了ouchsurfing.com凭据登录到该网站, 单击几下便获得了可以嵌入到couchsurfing.com个人资料中的html代码, 瞧-你的日历自动更新了你的个人资料。以下是日历的屏幕截图, 下面是有关如何制作日历的文章:

  • http://nderkach.github.io/blog/2013/11/17/hacking-couchsurfing-dot-org-api/
  • http://nderkach.github.io/blog/2013/11/24/hacking-couchsurfing-dot-org-api-part-2/
日历示例

我为Couchsurfing创建了一个很棒的功能, 我自然地认为他们会喜欢我的工作-甚至可能为我提供了他们开发团队中的职位。我已将电子邮件发送至jobs(at)couchsurfing.com, 并提供了指向该网站, 我的简历和参考的链接。我的一位网上冲浪客人留下的感谢信:

谢谢。

几天后, 他们跟进了我的逆向工程工作。在答复中, 很明显, 他们唯一关心的是自己的安全性, 因此他们要求我删除我撰写的有关API的博客文章, 最后删除该网站。我立即删除了这些信息, 因为我的意图不是违反使用条款并窃取用户凭据, 而是为了帮助Couch冲浪社区。我的印象是我被视为罪犯, 而公司仅关注我的网站需要用户凭据的事实。

我建议免费给他们我的应用程序。他们可以将其托管在自己的环境中, 并通过Facebook身份验证进行连接。毕竟, 这是一个很棒的功能, 社区需要它。这是我收到的最终解决方案:

假期过后, 我们又回到了这里, 希望跟进。

我们已经就你的应用程序进行了内部讨论, 以及如何既能体现应用程序的创造力又能发挥主动性, 同时又不会在用户将其凭据输入第三方站点时损害Couchsurfing用户数据的隐私和安全性。

日历显然填补了我们网站上的一个功能漏洞, 该功能是我们目前正在处理的较大项目的一部分。

但是收集用户名和密码的问题仍然存在。我们无法提供一种简单的设置方法, 因此我们可以在不让你访问该数据或将你的网站视为我们的工作产品的情况下在我们这方面进行托管或支持。

当前可用的API很快将被需要访问它的应用程序进行身份验证/授权的版本所取代。”

今天, 尽管我正在撰写此逆向工程软件教程(活动结束后的一年), 但Couchsurfing仍未实现日历功能。

回到纯真-再一次入侵我的Couch

几周前, 我受到鼓舞, 写了一篇有关逆向工程私有API的技术的文章。自然, 我决定总结我之前写过的关于该主题的文章, 并增加一些其他细节。当我开始撰写新文章时, 我想展示使用最新API的逆向工程过程, 并深入探讨API hacking。根据我以前的经验, 以及Couchsurfing最近发布了一个全新的wesbite和移动应用程序http://blog.couchsurfing.com/the-future-of-couchsurfing-is-on-the-way/, 这一事实, 决定再次修改其API。

我为什么要进行逆向工程?嗯, 首先, 通常来说, 逆向工程软件很有趣。我特别喜欢它, 因为它不仅涉及你的技术技能, 还涉及你的直觉。有时, 解决问题的最佳方法是进行有根据的猜测-与蛮力相比, 它可以节省很多时间。最近, 我听到了一家公司的故事, 该公司必须使用专有API且几乎没有文档。他们几天来一直在努力以未知格式解密API响应有效载荷, 然后有人决定在URL末尾尝试?decode = true, 并且使用了正确的JSON。有时, 如果幸运的话, 你所需要做的就是整理JSON响应。

我执行本教程的另一个原因是, 某些公司要花一些时间才能采用其用户要求的特定功能。无需等待其实现, 你就可以利用他们的私有API的功能自行构建。

因此, 使用新的couchsurfing.com API, 我从类似的方法入手, 并安装了他们最新的iOS应用。

首先, 你需要在局域网中设置代理, 以通过执行中间人攻击(MITM)伪造从应用程序到API的HTTP请求。

对于未加密的连接, 攻击非常简单-客户端连接到代理, 然后将来回请求来回中继到目标服务器。如有必要, 你可以修改有效负载。在公共WLAN中, 通过伪装WiFi路由器很容易在变相下执行此操作。

对于加密连接, 有一个小的区别:所有请求都是端到端加密的。除非攻击者以某种方式可以访问私钥(在交互过程中当然不会发送私钥), 否则攻击者无法解密该消息。话虽如此, 即使API通信通道是安全的, 端点(尤其是客户端)也不是那么安全。

为了使SSL正常运行, 必须满足以下条件:

  • 服务器的证书必须使用受信任的证书颁发机构(CA)签名
  • 证书中服务器的通用名称必须与服务器的域名匹配

为了克服MITM攻击中的加密, 我们的代理需要充当CA(证书颁发机构)并即时生成证书。例如, 如果客户端尝试连接到www.google.com, 则代理将为www.google.com动态创建证书并对其进行签名。现在, 客户认为代理实际上是www.google.com

此图概述了逆向工程专用API的步骤。

为了实现用于逆向工程私有API的嗅探代理, 我将使用称为mitmproxy的工具。你可以使用任何其他透明HTTPS代理。查尔斯(Charles)是另一个具有出色GUI的示例。为了完成这项工作, 我们需要设置以下内容:

将手机的WiFi连接默认网关配置为代理(以便代理位于中间, 所有数据包都通过)在手机上安装代理的证书(以便客户端在其信任库中拥有代理的公钥)

查看有关安装证书的代理人文档。这是三甲氧基的说明。这是iOS的证书PEM文件。

要监视拦截的HTTP请求, 你只需启动mitmproxy并从手机连接到它(默认端口为8080)。

手机设置。

在你的移动浏览器中打开一个网站。此时, 你应该可以看到mitmproxy中的流量。

一旦确认一切正常,就可以开始逆向软件工程。

确保一切都按计划进行后, 就该开始探索你选择的私有API了。基本上, 到此为止, 你只需打开应用程序, 对其进行操作, 并获得有关API端点和请求结构的想法。

对于如何对软件API进行逆向工程, 没有严格的算法-大多数时候, 你都依赖直觉并做出假设。

我的方法是复制API调用并使用不同的选项。一个好的开始是重播你在mitmproxy中捕获的请求, 并查看它是否有效(按” r”重播请求)。第一步是弄清楚哪些标题是必需的。使用带有mitmproxy的标题播放非常方便:按” e”进入编辑模式, 然后按” h”修改标题。通过使用捷径, 病毒成瘾者会感到宾至如归。你还可以使用诸如Postman之类的浏览器扩展来测试API, 但它们往往会添加不必要的标头, 因此我建议坚持使用mitmproxy或curl。

我制作了一个脚本, 可以读取mitmproxy转储文件并生成一个curl字符串-https://gist.github.com/nderkach/bdb31b04fb1e69fa5346

让我们从登录时发送的请求开始。

POST https://hapi.couchsurfing.com/api/v2/sessions
← 200 application/json
本逆向工程教程的第一步是复制API调用并使用生成的选项。

我注意到的第一件事是, 每个请求都包含一个强制性标头X-CS-Url-Signature, 每次都不同。我还尝试过一段时间后重播一个请求, 以检查服务器上是否有时间戳记检查, 并且没有。下一步是弄清楚该签名是如何计算的。

在这一点上, 我决定对二进制文件进行逆向工程并找出算法。自然, 在拥有为iPhone开发的经验和拥有iPhone的经验后, 我决定从iPhone ipa(可交付iPhone应用程序)开始。原来要解密一个, 我需要一部越狱的手机。停止!锤击时间。

然后, 我记得他们也有一个Android应用程序。我有点犹豫尝试这种方法, 因为我对Android或Java一无所知。然后, 我认为这是学习新知识的好机会。事实证明, 与高度优化的iphone机器代码相比, 通过反编译java字节码来获得易于理解的准源代码是比较容易的。

Apk(可交付的Android应用)基本上是一个zip文件。你可以使用任何zip提取器解压缩其内容。你将找到一个名为classes.dex的文件, 该文件是Dalvik字节码。 Dalvik是一个虚拟机, 用于在Android上运行翻译后的Java字节码。

为了将.dex文件反编译为.java源代码, 我使用了名为dex2jar的工具。该工具的输出是一个jar文件, 你可以使用多种工具对其进行反编译。你甚至可以在Eclipse或IntelliJ IDEA中打开一个jar, 它将为你完成所有工作。这些工具大多数都会产生相似的结果。我们并不在乎是否可以将其重新编译以运行它, 而只是在使用它来分析源代码。

这是我尝试过的工具列表:

  • FernFlower(现已成为IntelliJ IDEA的一部分)
  • CFR
  • 图形界面
  • 喀拉喀托
  • Procyon

CFR和FernFlower对我来说效果最好。 JD-GUI无法反编译代码的某些关键部分, 因而毫无用处, 而其他的质量几乎相同。幸运的是, 似乎尚未对Java代码进行混淆, 但是ProGuard之类的工具可以http://developer.android.com/tools/help/proguard.html之类的工具来对代码进行混淆。

Java反编译并不是本逆向工程教程的真正内容-有关该主题的文章很多, 因此, 假设你已成功反编译和反混淆了Java代码。

我在以下要点中结合了用于计算X-CS-Url-Signature的所有相关代码:https://gist.github.com/nderkach/d11540e9af322f1c1c74

首先, 我搜索了RetrofitHttpClient中提到的X-CS-Url-Signature。一个特定的调用似乎很有趣-对EncUtils模块。深入研究它, 我意识到他们正在使用HMAC SHA1。 HMAC是消息身份验证代码, 它使用加密功能(在这种情况下为SHA1)来计算消息的哈希。它用于确保完整性(即防止中间人修改请求)和身份验证。

我们需要两件事来计算X-CS-Url-Signature:私钥和编码后的消息(可能是HTTP请求有效负载和URL的某些变体)。

final String a2 = EncUtils.a(EncUtils.a(a, s));
 
final ArrayList<Header> list = new ArrayList<Header>(request.getHeaders());
list.add(new Header("X-CS-Url-Signature", a2));

在代码中, a是消息, 而s是用于计算标头a2的密钥(对EncUtils的两次调用仅计算HMAC SHA1十六进制摘要)。

查找密钥不是问题-它以纯文本格式存储在ApiModule中, 并用于初始化RetrofitHttpClient的第二个参数。

RetrofitHttpClient a(OkHttpClient okHttpClient) {
    return new RetrofitHttpClient(okHttpClient, "v3#[email protected]#XreXeGCh");
}

如果我们看一下对EncUtils的调用, 可以看到上面的字符串文字被逐字用作计算HMAC的键, 除非在定义this.b的情况下。在后一种情况下, this.b将附加一个点。

String s;
if (this.b == null) {
    s = this.a;
}
else {
    s = this.a + "." + this.b;
}

现在, 仅通过查看代码, 我还不清楚this.b的初始化位置和初始化方式(我唯一能发现的是它是在带有签名this.a(String b)的方法中调用的, 但我在代码的任何地方都找不到对它的调用)。

public void a(final String b) {
    this.b = b;
}

我鼓励你对它进行反编译并找出自己的地方:)

弄清楚消息是很直接的-在代码中, 你可以看到它是url路径(即/ api / v2 / sessions)和带有JSON有效负载的字符串(如果有)的串联。

final byte[] b = this.b(request.getUrl());
byte[] a;
if (request.getBody() != null && request.getBody() instanceof JsonTypedOutput) {
    System.out.println("body");
    // this.a(x, y) concatenates byte arrays  
    a = this.a(b, ((JsonTypedOutput)request.getBody()).a);
}
else {
    a = b;
}

仅通过查看代码, 就很难找出用于HMAC计算的确切算法。因此, 我决定使用调试符号重新构建应用程序, 以准确了解应用程序的工作方式。我使用了一个名为apktool https://code.google.com/p/android-apktool/的工具, 通过smali https://code.google.com/p/smali/散布Dalvik字节码。我在https://code.google.com/p/android-apktool/wiki/SmaliDebugging中遵循了指南

生成apk后, 你需要签名并将其安装在设备上。由于我没有Android设备, 因此我使用了Android SDK随附的模拟器。使用一些勺子喂食, 这是你的操作方法:

jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android <path_to_your_built_apk> androiddebugkey

jarsigner -verify -verbose -certs <path_to_your_built_apk>

zipalign -v 4 <path_to_your_built_apk> <path_to_your_output_signed_apk>

我使用了内置的Android仿真器, 该软件随附sdk和启用HAXM的Atom x86虚拟映像, 以确保其平稳运行。

tools/emulator -avd mydroid -no-boot-anim -cpu-delay 0

这是有关如何设置虚拟映像的不错指南:http://jolicode.com/blog/speed-up-your-android-emulator

确保看到HAX行正在运行, 并且在模拟器启动时模拟器以快速virt模式运行, 以确保已启用HAXM。

然后, 我将apk安装到模拟器中并运行了该应用程序。按照apktool指南, 我利用IntelliJ IDEA远程调试器连接到仿真器并设置了一些断点:

一些逆向工程技术涉及运行应用程序并仅查看发生的情况。

玩了一下该应用程序, 我能够确定用于初始化RetrofitHttpClient的私钥用于计算登录请求签名的HMAC。在对登录POST的响应中, 你将收到一个用户ID和accessToken(X-Access-Token)。访问令牌用于授权以下所有请求。用于所有发布后登录请求的HMAC与登录请求的构造方式相同, 不同之处在于, 密钥是通过将。<user_id>附加到原始私钥中来构成的。

这显示了逆向工程此私有API所需的授权过程。

获得授权后, 该应用会发送以下请求:

POST https://hapi.couchsurfing.com/api/v2/users/1003669205/registerDevice
← 200 application/json

正如我能够凭经验推断的那样, 此请求对于身份验证是可选的。如果你知道它的用处, 即可获得加分!

通过身份验证后, 你可以发送请求以获取你(或其他任何人的用户个人资料), 如下所示:

GET https://hapi.couchsurfing.com/api/v2/users/1003669205
← 200 application/json
在此逆向工程过程中,你可以获取任何人的用户个人资料。

我没有详细介绍, 但是我注意到配置文件已通过PUT请求进行了更新。只是为了好玩, 我尝试用相同的请求更新另一个配置文件-该配置文件未经授权, 因此显然实现了安全性基础。

我编写了一个简单的Python脚本, 使用你的ouchsurfing.com凭据登录并获取你的用户个人资料:https://gist.github.com/nderkach/899281d7e6dd0d497533。这是API的Python包装器:https://github.com/nderkach/couchsurfing-python, 在pypi储存库中有可用的软件包(pip installouchsurfing)。

下一步

我不确定这次要如何处理该API。用户配置文件中的HTML代码已不再被允许, 因此我必须提出一种解决旧问题的不同方法。如果有需求, 我将继续开发和增强python API包装器, 并假设ouchsurfing.com不会引起太多问题。我没有过多地研究API, 只是对其一些基本漏洞进行了测试。看起来已经足够安全了, 但是找出你是否可以访问该网站无法提供的数据将很有趣。无论哪种方式, 现在你都可以使用我的逆向软件工程来为Windows Phone, Pebble或智能Couch构建替代客户端。

最后一个问题

我想打开一个讨论-为什么不发布你的API并将其公开?即使我没有设法破解该API, 也仍然可以抓取该网站。这样会更慢且更难以维护, 但可以肯定的是, 他们希望消费者使用API​​而不是网络抓取工具。 API的可用性将使第三方开发人员可以改进公司的产品, 并围绕该产品构建增值服务。有人可能会说, 维护公共API会比维护私有API更为昂贵。但是话又说回来, 在产品之上建立社区服务的优势将超过API维护成本。

是否有可能完全阻止第三方客户端使用私有API?我不这么认为。如前所述, 使用SSL固定将防止使用简单的透明代理技术嗅探到API请求。最后, 即使你混淆了二进制文件, 具有某些资源和时间的有动机的黑客也将始终能够对应用程序二进制文件进行逆向工程并获得私钥/证书。我认为客户端端点是安全的这一假设本质上是错误的。 API客户端是一个薄弱环节。

通过保持API私有, 公司基本上可以将不信任的信息传达给用户。当然, 你可以尝试进一步保护私有API。但是, 你是否愿意为API实施基本安全措施以防止恶意使用;而是将你的资源集中在改进软件上以提供更好的用户体验?

不错, 请在Couchsurfing上加糖, 打开API。

赞(0)
未经允许不得转载:srcmini » 逆向工程软件专用API的教程:破解你的Couch

评论 抢沙发

评论前必须登录!