Contents

Agile Mock API for Reverse Engineering: An Example with Krisp

When testing (po) test (jie) software, the last thing I want to encounter is that the target software has the function of network verification. Say you want to change the code, but you don’t know where there are hidden stubs in the code, and it is very troublesome to change all the input and output points. Said to cut off its Internet cafes, and not all software provides the function of offline activation. Today I will introduce a network verification bypass method with four or two tricks, no need to disconnect the network, less bytecode changes, and less than 100 lines of Python. No loss, no evaporation, zero waste1.

Recently, I always use corporate WeChat online meetings for work and meetings. I have to cast the screen on the computer, and I have to turn on the microphone (I can’t log in multiple times, so I can’t use the microphone of the mobile phone). The sound quality of the computer microphone is really rubbish, and there is environmental noise. I searched and found a software Krisp2, which does audio processing at the sound card driver layer and global noise reduction, which is very suitable for the application scenario I expected. It’s a pity that it costs money. Since there is no solution on the Internet, we can only use our ingenuity to “learn” it.

Application Analysis

In the first step of reverse engineering, we must first know what programming language the software we want to reverse uses. The software Krisp is very simple. Open the installation directory, and you can see from the *.exe.config file and the Newtonsoft.Json library it refers to that this software is written in C#.

/2020/mitmproxy-mock-api/00.png

It’s simple in C#. Just drag it into dnSpy3 to open it. This tool is much more powerful than ILSpy back then. It can decompile, debug, and modify program logic directly with C#. Moreover, many .NET framework programs are published without confusion, and the variable and method names are written clearly. If you decompile it with dnSpy, it is basically the same as looking at the source code of the program.

/2020/mitmproxy-mock-api/01.png

Search for common keywords in dnSpy. Through the keyword trial (trial), you can quickly locate the Krisp.UI.ViewModels.KrispAppPageViewModel.UserProfileInfoChanged function. In addition to trial, there is another mode called unlimited in this function. Directly use dnSpy to change it without thinking.

/2020/mitmproxy-mock-api/02.png

Well, at least the trial restrictions on the interface are gone, and on the surface it is already a distinguished VIP customer.

/2020/mitmproxy-mock-api/03.png

But this is not enough, because this is just a logical judgment related to the UI in the program, and there must be many similar modification points. Many logical judgments are realized by comparing with constants, which is not easy to find, and it is too troublesome to modify one by one.

So let’s change our thinking. The program authorization status is sent from the network, so we might as well use network communication as the entry point. Use the Fiddler we mentioned in the last article to capture the packet, it is still very simple, you can find the API https://api.krisp.ai/v2/user/profile/2/1 casually.

/2020/mitmproxy-mock-api/04.png

Then what do we have to change it to? First, the data.mode.name parameter in JSON has to be changed to unlimited. Second, there are a lot of available=True parameter values ​​in data.settings below, and these will definitely become False after the trial period (the account I registered has not yet passed the trial period, so just guessing). So when we intercept the data and modify the JSON, just fix these values ​​as they are now.

Comparison of cracking methods

Well, our favorite “why not use xxxxx” link is here again. There are not many contestants participating today, ~~ Besides, I didn’t search for it~~. Simply compare.

** Method 1: Modify the API URL to a self-built API and perform MITM ** (final selection)

Advantages: There are fewer points that need to be modified in the program, just change the URL string. If you can construct a URL with the same length, you don’t even need a decompilation tool to change the source program, just replace the string directly. After the subsequent update of the program, the workload of maintaining the cracked version is very small.

Method 2: Modify the client and modify the return value at the REST API request point

Disadvantage: To crack the new version, you have to go through all the steps again. Moreover, requests from different APIs may still be in different Classes. It takes a lot of energy to crack it once.

Method 3: Change hosts to intercept API requests

Not feasible, the API access in the production environment is https. This is not a traditional MITM attack, and sslstrip cannot be used. If the network is disconnected, there is no way to log in and use normally, and the normal functions are destroyed.

And the framework for building the API is ~~ I said in the last article that it is rubbish~~ mitmproxy. As the name suggests, this framework is used as a middleman. The biggest difference between it and other programming language libraries is that it provides an API for * Revise * web requests (close to the middleware functions in other frameworks), while other web frameworks provide * Revise * 21"/> Web request capability. For example, Django, it parses the web request out of fields and throws it to us, so the request cannot be sent out. If I want to send this request again, I have to put all the fields together again and call requests to send it. What if the target application has dozens of APIs? trouble? We write code, only deal with the most important logic, do not write boring CRUD, really do it, no loss, no evaporation, zero waste1!

Other MITM tools are not applicable here. Can other tools be placed in a docker container and run on a VPS 24 hours a day?

Mock API construction

The most important function of the copycat API we built is that it allows us to modify incoming requests and return data in a way similar to writing middleware, and at the same time pass back the unmodified API intact. Of course, the less code you write, the better.

Now that the principles and tools are clarified, we just write the code according to the documentation. But when it comes to documentation, I have to remind you that mitmproxy has no documentation at all (smile). According to the author’s experience, some sample scripts 4567 in the project Github, and the pydoc command line 8 are two kinds of good reference materials. I can barely write according to the picture.

When we run mitmproxy, we need to use its reverse proxy mode 9. In this mode, mitmproxy will accept ordinary HTTP requests as input instead of special HTTP Proxy requests. The complete operating parameters are as follows:

mitmproxy -p 8081 -s krisp.py --mode reverse:http://localhost --set keep_host_header

Among them, the host name after reverse: can be entered casually, with the keep_host_header option, at the same time manually set the Host field in the request header as the destination host of the flow in the code, the only way to achieve ** Simultaneously reverse proxy multiple destination hosts ** on the same port.

The function 47 realized by the following piece of code:

  1. Redirect api.krisp.your.domain request to api.krisp.ai to implement reverse proxy.
  2. Return false return value for all requests to analytics.krisp.ai.
  3. Return 404 for other hosts.

/2020/mitmproxy-mock-api/05.png

The request function we defined in the above code is the event API provided by mitmproxy, and this function will be called before each request is sent. Next, we will implement another response function. This API will be triggered after mitmproxy obtains the return data of the web request (similar to the idea in the previous article).

And what we have to do is very simple, just realize all the modifications to data.mode.name and data.settings that we mentioned earlier.

/2020/mitmproxy-mock-api/06.png

Finally, define the class and declare the plug-in list according to the format in the code example, and then you can run mitmdump to call this script. Here, we name it krisp.py and listen for API requests on port 8081. mitmdump is different from mitmproxy. The latter is a TUI program with a user interface. The former is purely running and has no interface. It can be compared to tcpdump of the http protocol. This is very suitable for long-term operation.

mitmdump -p 8081 -s krisp.py --mode reverse:http://localhost --set keep_host_header

Of course, it is impossible for us to run such a line of command every time we open the software, how low. We can package it into a Docker container and put it on the server, so that it can be left open all the time.

/2020/mitmproxy-mock-api/07.png

If readers want to deploy an activation server that exposes the public network and runs continuously, it is recommended to hang an additional reverse generation in front, so that log rotate and rate limit are more convenient. The easiest way is to use docker compose to set a traefik in front, so that You don’t even have to worry about SSL certificates yourself. However, this part of the configuration is out of the scope of this article.

last minor modification

We set up a fake API that has to be used by the target program. It’s also very simple. Didn’t the packet capture just now capture two domain names, api.krisp.ai and analytics.krisp.ai. Directly change the global search to your own domain name and the port that mitmdump listens on, and that’s it.

/2020/mitmproxy-mock-api/08.png

epilogue

This article is another tutorial for lazy people. Two tools, less than 100 lines of code, implement a magic modified REST API, and crack an application in a relatively simple way. Some people will say that your C# program is not confused and has no shell. Isn’t it amused by such a simple reverse engineering? But think again, based on the idea of ​​capturing packets, even if the target application is a black box, guessing the meaning of the API parameters is still easier than guessing the value of the register. The most important thing is the idea of ​​building Web API and the usage of mitmproxy framework. These may be treasures of knowledge that can be used in other scenarios.

cover picture:

/2020/mitmproxy-mock-api/09.jpg

References


  1. Jinkela | All-Star Wiki | Fandom https://guichu.fandom.com/wiki/%E9%87%91%E5%9D%B7%E5%9E%83 ↩︎ ↩︎

  2. Noise Canceling App https://krisp.ai/ ↩︎

  3. 0xd4d/dnSpy: .NET debugger and assembly editor https://github.com/0xd4d/dnSpy ↩︎

  4. Example attack scenario: DNS forgery. https://github.com/mitmproxy/mitmproxy/blob/ed68e0a1ba/examples/contrib/dns_spoofing.py ↩︎ ↩︎

  5. Attack scenario example: TLS passthrough prevents the target host from discovering CA exceptions. https://github.com/mitmproxy/mitmproxy/blob/ed68e0a1ba/examples/contrib/tls_passthrough.py ↩︎

  6. Plugin example: Redirect intercepted requests. https://github.com/mitmproxy/mitmproxy/blob/ed68e0a1ba/examples/addons/http-redirect-requests.py ↩︎

  7. Plug-in example: Forge the return data so that the remote server cannot receive any messages. https://github.com/mitmproxy/mitmproxy/blob/ed68e0a1ba/examples/addons/http-reply-from-proxy.py ↩︎ ↩︎

  8. Run pydoc mitmproxy.http (application layer related APIs, such as http.HTTPFlow and http.HTTPRequest) and http.HTTPRequest in the venv of mitmproxy r=“49”/> (transport layer-related API, obtain source IP, source port and other information) to obtain API documents. ↩︎

  9. Modes of operation - mitmproxy https://docs.mitmproxy.org/stable/concepts-modes/ ↩︎