Merge pull request #4064 from TeddJohnson/patch-1

Update concepts-certificates.md
This commit is contained in:
Maximilian Hils 2020-07-04 11:51:25 +02:00 committed by GitHub
commit 491123df23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 180 additions and 180 deletions

View File

@ -23,16 +23,16 @@ Let's begin with a simple example.
To see this example in action, start mitmproxy console with the addon loaded: To see this example in action, start mitmproxy console with the addon loaded:
{{< highlight bash >}} ```bash
> mitmproxy -s ./examples/addons/commands-simple.py > mitmproxy -s ./examples/addons/commands-simple.py
{{< /highlight >}} ```
Now, make sure the event log is showing, and then execute the command at the Now, make sure the event log is showing, and then execute the command at the
prompt (started by typing ":"): prompt (started by typing ":"):
{{< highlight none>}} ```
:myaddon.inc :myaddon.inc
{{< /highlight >}} ```
Notice that tab completion works - our addon command has complete parity with Notice that tab completion works - our addon command has complete parity with
builtin commands. There are a few things to note about this example: builtin commands. There are a few things to note about this example:
@ -67,28 +67,28 @@ filters]({{< relref addons-options >}}) available. Let's try it out.
Start by loading the addon into mitmproxy and sending some traffic through so we Start by loading the addon into mitmproxy and sending some traffic through so we
have flows to work with: have flows to work with:
{{< highlight bash >}} ```bash
> mitmproxy -s ./examples/addons/commands-flows.py > mitmproxy -s ./examples/addons/commands-flows.py
{{< /highlight >}} ```
We can now invoke our toy command in various ways. Let's begin by running it We can now invoke our toy command in various ways. Let's begin by running it
just on the currently focused flow: just on the currently focused flow:
{{< highlight none >}} ```
:myaddon.addheader @focus :myaddon.addheader @focus
{{< /highlight >}} ```
We can also invoke it on all flows: We can also invoke it on all flows:
{{< highlight none >}} ```
:myaddon.addheader @all :myaddon.addheader @all
{{< /highlight >}} ```
Or only flows from **google.com**: Or only flows from **google.com**:
{{< highlight none >}} ```
:myaddon.addheader ~d google.com :myaddon.addheader ~d google.com
{{< /highlight >}} ```
What's more, we can trivially bind these commands to keyboard shortcuts within What's more, we can trivially bind these commands to keyboard shortcuts within
mitmproxy if we plan to use them frequently. Flow selectors combined with mitmproxy if we plan to use them frequently. Flow selectors combined with
@ -107,9 +107,9 @@ Our command calculates a histogram of the domains in the specified set of flows,
and writes it to a path which is specified as the second argument to the and writes it to a path which is specified as the second argument to the
command. Try invoking it like this: command. Try invoking it like this:
{{< highlight none >}} ```
:myaddon.histogram @all /tmp/xxx :myaddon.histogram @all /tmp/xxx
{{< /highlight >}} ```
Notice that mitmproxy provides tab completion both for the flow specification Notice that mitmproxy provides tab completion both for the flow specification
and the path. and the path.

View File

@ -28,15 +28,15 @@ allows addons declare options and commands. In this case, the addon adds a
single `addheader` option with type `bool`. Let's try this out by running the single `addheader` option with type `bool`. Let's try this out by running the
script in mitmproxy console: script in mitmproxy console:
{{< highlight bash >}} ```bash
> mitmproxy -s ./examples/addons/options-simple.py > mitmproxy -s ./examples/addons/options-simple.py
{{< /highlight >}} ```
You can now use CURL to make a request through the proxy like this: You can now use CURL to make a request through the proxy like this:
{{< highlight bash >}} ```bash
> env http_proxy=http://localhost:8080 curl -I http://google.com > env http_proxy=http://localhost:8080 curl -I http://google.com
{{< /highlight >}} ```
If you run this request immediately, you'll notice that no count header is If you run this request immediately, you'll notice that no count header is
added. This is because our default value for the option was `false`. Press `O` added. This is because our default value for the option was `false`. Press `O`
@ -45,22 +45,22 @@ mitmproxy knows this is a boolean, and lets you toggle the value between true
and false. Set the value to `true`, and you should see a result something like and false. Set the value to `true`, and you should see a result something like
this: this:
{{< highlight bash >}} ```bash
> env http_proxy=http://localhost:8080 curl -I http://google.com > env http_proxy=http://localhost:8080 curl -I http://google.com
HTTP/1.1 301 Moved Permanently HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/ Location: http://www.google.com/
Content-Length: 219 Content-Length: 219
count: 1 count: 1
{{< /highlight >}} ```
When this addon is loaded, the `addheader` setting is available in the When this addon is loaded, the `addheader` setting is available in the
persistent [YAML configuration file]({{< relref "concepts-options" >}}). You can persistent [YAML configuration file]({{< relref "concepts-options" >}}). You can
also over-ride the value directly from the command-line for any of the tools also over-ride the value directly from the command-line for any of the tools
using the `--set` flag: using the `--set` flag:
{{< highlight bash >}} ```bash
mitmproxy -s ./examples/addons/options-simple.py --set addheader=true mitmproxy -s ./examples/addons/options-simple.py --set addheader=true
{{< /highlight >}} ```
## Handling configuration updates ## Handling configuration updates
@ -85,11 +85,11 @@ called with our default value (`None`), and then later with an updated value if
the option is changed. If we try to load the script with an incorrect value, we the option is changed. If we try to load the script with an incorrect value, we
now see an error: now see an error:
{{< highlight none >}} ```
> mitmdump -s ./examples/addons/options-configure.py --set addheader=1000 > mitmdump -s ./examples/addons/options-configure.py --set addheader=1000
Loading script: ./examples/addons/options-configure.py Loading script: ./examples/addons/options-configure.py
/Users/cortesi/mitmproxy/mitmproxy/venv/bin/mitmdump: addheader must be <= 100 /Users/cortesi/mitmproxy/mitmproxy/venv/bin/mitmdump: addheader must be <= 100
{{< /highlight >}} ```
## Supported Types ## Supported Types

View File

@ -34,9 +34,9 @@ command-line is to use [pydoc](https://docs.python.org/3/library/pydoc.html).
Here, for example, is a command that shows the API documentation for the Here, for example, is a command that shows the API documentation for the
mitmproxy's HTTP flow classes: mitmproxy's HTTP flow classes:
{{< highlight bash >}} ```bash
pydoc mitmproxy.http pydoc mitmproxy.http
{{< /highlight >}} ```
You will be referring to the mitmproxy API documentation frequently, so keep You will be referring to the mitmproxy API documentation frequently, so keep
**pydoc** or an equivalent handy. **pydoc** or an equivalent handy.
@ -54,9 +54,9 @@ Take it for a spin and make sure that it does what it's supposed to, by loading
it into your mitmproxy tool of choice. We'll use mitmpdump in these examples, it into your mitmproxy tool of choice. We'll use mitmpdump in these examples,
but the flag is identical for all tools: but the flag is identical for all tools:
{{< highlight bash >}} ```bash
> mitmdump -s ./anatomy.py > mitmdump -s ./anatomy.py
{{< /highlight >}} ```
Here are a few things to note about the code above: Here are a few things to note about the code above:

View File

@ -47,9 +47,9 @@ documentation for some common platforms. The mitmproxy CA cert is located in
- [Windows](https://web.archive.org/web/20160612045445/http://windows.microsoft.com/en-ca/windows/import-export-certificates-private-keys#1TC=windows-7) - [Windows](https://web.archive.org/web/20160612045445/http://windows.microsoft.com/en-ca/windows/import-export-certificates-private-keys#1TC=windows-7)
- [Windows (automated)](https://technet.microsoft.com/en-us/library/cc732443.aspx) - [Windows (automated)](https://technet.microsoft.com/en-us/library/cc732443.aspx)
{{< highlight bash >}} ```bash
certutil -addstore root mitmproxy-ca-cert.cer certutil -addstore root mitmproxy-ca-cert.cer
{{< / highlight >}} ```
- [Mac OS X](https://support.apple.com/kb/PH20129) - [Mac OS X](https://support.apple.com/kb/PH20129)
- [Ubuntu/Debian]( https://askubuntu.com/questions/73287/how-do-i-install-a-root-certificate/94861#94861) - [Ubuntu/Debian]( https://askubuntu.com/questions/73287/how-do-i-install-a-root-certificate/94861#94861)
@ -117,26 +117,26 @@ file roughly looks like this:
For example, you can generate a certificate in this format using these For example, you can generate a certificate in this format using these
instructions: instructions:
{{< highlight bash >}} ```bash
openssl genrsa -out cert.key 2048 openssl genrsa -out cert.key 2048
# (Specify the mitm domain as Common Name, e.g. \*.google.com) # (Specify the mitm domain as Common Name, e.g. \*.google.com)
openssl req -new -x509 -key cert.key -out cert.crt openssl req -new -x509 -key cert.key -out cert.crt
cat cert.key cert.crt > cert.pem cat cert.key cert.crt > cert.pem
{{< / highlight >}} ```
Now, you can run mitmproxy with the generated certificate: Now, you can run mitmproxy with the generated certificate:
**For all domain names** **For all domain names**
{{< highlight bash >}} ```bash
mitmproxy --cert *=cert.pem mitmproxy --cert *=cert.pem
{{< / highlight >}} ```
**For specific domain names** **For specific domain names**
{{< highlight bash >}} ```bash
mitmproxy --cert *.example.com=cert.pem mitmproxy --cert *.example.com=cert.pem
{{< / highlight >}} ```
**Note:** `*.example.com` is for all the subdomains. You can also use **Note:** `*.example.com` is for all the subdomains. You can also use
`www.example.com` for a particular subdomain. `www.example.com` for a particular subdomain.

View File

@ -27,9 +27,9 @@ browser (by default accessible with the `C` key binding).
Many of mitmproxy's commands take flows as arguments. For instance, the Many of mitmproxy's commands take flows as arguments. For instance, the
signature for the client replay commands looks like this: signature for the client replay commands looks like this:
{{< highlight none >}} ```
replay.client [flow] replay.client [flow]
{{< /highlight >}} ```
That means that it expects a sequence of one or more flows. This is where [flow That means that it expects a sequence of one or more flows. This is where [flow
@ -40,23 +40,23 @@ invoking commands.
Fire up mitmproxy console, and intercept some traffic so we have flows to work Fire up mitmproxy console, and intercept some traffic so we have flows to work
with. Now type the following command: with. Now type the following command:
{{< highlight none >}} ```
:replay.client @focus :replay.client @focus
{{< /highlight >}} ```
Make sure you try using tab completion for the command name and the flow Make sure you try using tab completion for the command name and the flow
specification. The `@focus` specifiers expands to the currently focused flow, so specification. The `@focus` specifiers expands to the currently focused flow, so
you should see this flow replay. However, replay can take any number of flows. you should see this flow replay. However, replay can take any number of flows.
Try the following command: Try the following command:
{{< highlight none >}} ```
:replay.client @all :replay.client @all
{{< /highlight >}} ```
Now you should see all flows replay one by one. We have the full power of the Now you should see all flows replay one by one. We have the full power of the
mitmproxy filter language at our disposal here, so we could also, for example, mitmproxy filter language at our disposal here, so we could also, for example,
just replay flows for a specific domain: just replay flows for a specific domain:
{{< highlight none >}} ```
:replay.client "~d google.com" :replay.client "~d google.com"
{{< /highlight >}} ```

View File

@ -25,9 +25,9 @@ usually reliable. In the simplest possible interaction with mitmproxy, a
client connects directly to the proxy, and makes a request that looks client connects directly to the proxy, and makes a request that looks
like this: like this:
{{< highlight http >}} ```http
GET http://example.com/index.html HTTP/1.1 GET http://example.com/index.html HTTP/1.1
{{< / highlight >}} ```
This is a proxy GET request - an extended form of the vanilla HTTP GET This is a proxy GET request - an extended form of the vanilla HTTP GET
request that includes a schema and host specification, and it includes request that includes a schema and host specification, and it includes
@ -47,9 +47,9 @@ The process for an explicitly proxied HTTPS connection is quite
different. The client connects to the proxy and makes a request that different. The client connects to the proxy and makes a request that
looks like this: looks like this:
{{< highlight http >}} ```http
CONNECT example.com:443 HTTP/1.1 CONNECT example.com:443 HTTP/1.1
{{< / highlight >}} ```
A conventional proxy can neither view nor manipulate a TLS-encrypted A conventional proxy can neither view nor manipulate a TLS-encrypted
data stream, so a CONNECT request simply asks the proxy to open a pipe data stream, so a CONNECT request simply asks the proxy to open a pipe
@ -91,9 +91,9 @@ blush, it seems that the CONNECT request above gives us all we need - in this
example, both of these values are "example.com". But what if the client had example, both of these values are "example.com". But what if the client had
initiated the connection as follows: initiated the connection as follows:
{{< highlight http >}} ```http
CONNECT 10.1.1.1:443 HTTP/1.1 CONNECT 10.1.1.1:443 HTTP/1.1
{{< / highlight >}} ```
Using the IP address is perfectly legitimate because it gives us enough Using the IP address is perfectly legitimate because it gives us enough
information to initiate the pipe, even though it doesn't reveal the information to initiate the pipe, even though it doesn't reveal the
@ -182,9 +182,9 @@ server - [iptables](http://www.netfilter.org/) on Linux or
client has initiated the connection, it makes a vanilla HTTP request, client has initiated the connection, it makes a vanilla HTTP request,
which might look something like this: which might look something like this:
{{< highlight http >}} ```http
GET /index.html HTTP/1.1 GET /index.html HTTP/1.1
{{< / highlight >}} ```
Note that this request differs from the explicit proxy variation, in Note that this request differs from the explicit proxy variation, in
that it omits the scheme and hostname. How, then, do we know which that it omits the scheme and hostname. How, then, do we know which

View File

@ -60,7 +60,7 @@ method to do so:
becomes \\.) and use this as your ignore pattern: becomes \\.) and use this as your ignore pattern:
{{< highlight none >}} ```
>>> mitmdump -v >>> mitmdump -v
127.0.0.1:50588: clientconnect 127.0.0.1:50588: clientconnect
127.0.0.1:50588: request 127.0.0.1:50588: request
@ -70,11 +70,11 @@ method to do so:
-> example.com:443 -> example.com:443
^C ^C
>>> mitmproxy --ignore-hosts ^example\.com:443$ >>> mitmproxy --ignore-hosts ^example\.com:443$
{{< /highlight >}} ```
Here are some other examples for ignore patterns: Here are some other examples for ignore patterns:
{{< highlight none >}} ```
# Exempt traffic from the iOS App Store (the regex is lax, but usually just works): # Exempt traffic from the iOS App Store (the regex is lax, but usually just works):
--ignore-hosts apple.com:443 --ignore-hosts apple.com:443
# "Correct" version without false-positives: # "Correct" version without false-positives:
@ -87,17 +87,17 @@ Here are some other examples for ignore patterns:
--ignore-hosts 17\.178\.96\.59:443 --ignore-hosts 17\.178\.96\.59:443
# IP address range: # IP address range:
--ignore-hosts 17\.178\.\d+\.\d+:443 --ignore-hosts 17\.178\.\d+\.\d+:443
{{< / highlight >}} ```
This option can also be used to whitelist some domains through negative lookahead expressions. However, ignore patterns are always matched against the IP address of the target before being matched against its domain name. Thus, the pattern must allow any IP addresses using an expression like `^(?![0-9\.]+:)` in order for domains whitelisting to work. Here are examples of such patterns: This option can also be used to whitelist some domains through negative lookahead expressions. However, ignore patterns are always matched against the IP address of the target before being matched against its domain name. Thus, the pattern must allow any IP addresses using an expression like `^(?![0-9\.]+:)` in order for domains whitelisting to work. Here are examples of such patterns:
{{< highlight none >}} ```
# Ignore everything but example.com and mitmproxy.org (not subdomains): # Ignore everything but example.com and mitmproxy.org (not subdomains):
--ignore-hosts '^(?![0-9\.]+:)(?!example\.com:)(?!mitmproxy\.org:)' --ignore-hosts '^(?![0-9\.]+:)(?!example\.com:)(?!mitmproxy\.org:)'
# Ignore everything but example.com and its subdomains: # Ignore everything but example.com and its subdomains:
--ignore-hosts '^(?![0-9\.]+:)(?!([^\.:]+\.)*example\.com:)' --ignore-hosts '^(?![0-9\.]+:)(?!([^\.:]+\.)*example\.com:)'
{{< / highlight >}} ```
**Footnotes** **Footnotes**

View File

@ -23,22 +23,22 @@ Please note, that apps can decide to ignore the system certificate store and mai
## 2. Rename certificate ## 2. Rename certificate
Enter your certificate folder Enter your certificate folder
{{< highlight bash >}} ```bash
cd ~/.mitmproxy/ cd ~/.mitmproxy/
{{< / highlight >}} ```
- CA Certificates in Android are stored by the name of their hash, with a '0' as extension - CA Certificates in Android are stored by the name of their hash, with a '0' as extension
- Now generate the hash of your certificate - Now generate the hash of your certificate
{{< highlight bash >}} ```bash
openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1 openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1
{{< / highlight >}} ```
Lets assume, the output is `c8450d0d` Lets assume, the output is `c8450d0d`
We can now copy `mitmproxy-ca-cert.cer` to `c8450d0d.0` and our system certificate is ready to use We can now copy `mitmproxy-ca-cert.cer` to `c8450d0d.0` and our system certificate is ready to use
{{< highlight bash >}} ```bash
cp mitmproxy-ca-cert.cer c8450d0d.0 cp mitmproxy-ca-cert.cer c8450d0d.0
{{< / highlight >}} ```
## 3. Insert certificate into system certificate store ## 3. Insert certificate into system certificate store
@ -50,37 +50,37 @@ Note, that Android 9 (API LEVEL 28) was used to test the following steps and tha
- Keep in mind, that the **emulator will load a clean system image when starting without `-writable-system` option**. - Keep in mind, that the **emulator will load a clean system image when starting without `-writable-system` option**.
- This means you always have to start the emulator with `-writable-system` option in order to use your certificate - This means you always have to start the emulator with `-writable-system` option in order to use your certificate
{{< highlight bash >}} ```bash
emulator -avd <avd_name_here> -writable-system emulator -avd <avd_name_here> -writable-system
{{< / highlight >}} ```
- Restart adb as root - Restart adb as root
{{< highlight bash >}} ```bash
adb root adb root
{{< / highlight >}} ```
- Get write access to `/system` on the device - Get write access to `/system` on the device
- In earlier versions (API LEVEL < 28) of Android you have to use `adb shell "mount -o rw,remount /system"` - In earlier versions (API LEVEL < 28) of Android you have to use `adb shell "mount -o rw,remount /system"`
{{< highlight bash >}} ```bash
adb shell "mount -o rw,remount /" adb shell "mount -o rw,remount /"
{{< / highlight >}} ```
- Push your certificate to the system certificate store and set file permissions - Push your certificate to the system certificate store and set file permissions
{{< highlight bash >}} ```bash
adb push c8450d0d.0 /system/etc/security/cacerts adb push c8450d0d.0 /system/etc/security/cacerts
adb shell "chmod 664 /system/etc/security/cacerts/c8450d0d.0" adb shell "chmod 664 /system/etc/security/cacerts/c8450d0d.0"
{{< / highlight >}} ```
## 4. Reboot device and enjoy decrypted TLS traffic ## 4. Reboot device and enjoy decrypted TLS traffic
- Reboot your device. - Reboot your device.
- You CA certificate should now be system trusted - You CA certificate should now be system trusted
{{< highlight bash >}} ```bash
adb reboot adb reboot
{{< / highlight >}} ```
**Remember**: You **always** have to start the emulator using the `-writable-system` option in order to use your certificate **Remember**: You **always** have to start the emulator using the `-writable-system` option in order to use your certificate

View File

@ -16,9 +16,9 @@ Internal Network* setup can be applied to other setups.
First, we have to find out under which name Ubuntu has mapped our network interfaces. You can find this information with: First, we have to find out under which name Ubuntu has mapped our network interfaces. You can find this information with:
{{< highlight bash >}} ```bash
ip link ip link
{{< / highlight >}} ```
Usually with Ubuntu and Virtualbox, **eth0** or **enp0s3** (Ubuntu 15.10 and newer) is connected to the internet and **eth1** or **enp0s8** (Ubuntu 15.10 and newer) is connected to the internal network that will be proxified and configured to use a static ip (192.168.3.1). If the names differ, use the ones you got from the *ip link* command. Usually with Ubuntu and Virtualbox, **eth0** or **enp0s3** (Ubuntu 15.10 and newer) is connected to the internet and **eth1** or **enp0s8** (Ubuntu 15.10 and newer) is connected to the internal network that will be proxified and configured to use a static ip (192.168.3.1). If the names differ, use the ones you got from the *ip link* command.
@ -46,27 +46,27 @@ case, this needs to be disabled by changing `dns=dnsmasq` to `#dns=dnsmasq` in
**/etc/NetworkManager/NetworkManager.conf** and if on Ubuntu 16.04 or newer **/etc/NetworkManager/NetworkManager.conf** and if on Ubuntu 16.04 or newer
running: running:
{{< highlight bash >}} ```bash
sudo systemctl restart NetworkManager sudo systemctl restart NetworkManager
{{< / highlight >}} ```
If on Ubuntu 12.04 or 14.04 running: If on Ubuntu 12.04 or 14.04 running:
{{< highlight bash >}} ```bash
sudo restart network-manager sudo restart network-manager
{{< / highlight >}} ```
afterwards. afterwards.
Now, dnsmasq can be be installed and configured: Now, dnsmasq can be be installed and configured:
{{< highlight bash >}} ```bash
sudo apt-get install dnsmasq sudo apt-get install dnsmasq
{{< / highlight >}} ```
Replace **/etc/dnsmasq.conf** with the following configuration: Replace **/etc/dnsmasq.conf** with the following configuration:
{{< highlight none >}} ```
# Listen for DNS requests on the internal network # Listen for DNS requests on the internal network
interface=eth1 interface=eth1
bind-interfaces bind-interfaces
@ -75,21 +75,21 @@ dhcp-range=192.168.3.10,192.168.3.100,96h
# Broadcast gateway and dns server information # Broadcast gateway and dns server information
dhcp-option=option:router,192.168.3.1 dhcp-option=option:router,192.168.3.1
dhcp-option=option:dns-server,192.168.3.1 dhcp-option=option:dns-server,192.168.3.1
{{< / highlight >}} ```
Apply changes: Apply changes:
If on Ubuntu 16.04 or newer: If on Ubuntu 16.04 or newer:
{{< highlight bash >}} ```bash
sudo systemctl restart dnsmasq sudo systemctl restart dnsmasq
{{< / highlight >}} ```
If on Ubuntu 12.04 or 14.04: If on Ubuntu 12.04 or 14.04:
{{< highlight bash >}} ```bash
sudo service dnsmasq restart sudo service dnsmasq restart
{{< / highlight >}} ```
Your **proxied machine** in the internal virtual network should now receive an Your **proxied machine** in the internal virtual network should now receive an
IP address via DHCP: IP address via DHCP:
@ -101,19 +101,19 @@ IP address via DHCP:
To redirect traffic to mitmproxy, we need to enable IP forwarding and add two iptables To redirect traffic to mitmproxy, we need to enable IP forwarding and add two iptables
rules: rules:
{{< highlight bash >}} ```bash
sudo sysctl -w net.ipv4.ip_forward=1 sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 8080 sudo iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 -j REDIRECT --to-port 8080 sudo iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 -j REDIRECT --to-port 8080
{{< / highlight >}} ```
## 4. Run mitmproxy ## 4. Run mitmproxy
Finally, we can run mitmproxy in transparent mode with Finally, we can run mitmproxy in transparent mode with
{{< highlight bash >}} ```bash
mitmproxy --mode transparent mitmproxy --mode transparent
{{< / highlight >}} ```
The proxied machine cannot to leak any data outside of HTTP or DNS requests. If The proxied machine cannot to leak any data outside of HTTP or DNS requests. If
required, you can now [install the mitmproxy certificates on the proxied required, you can now [install the mitmproxy certificates on the proxied

View File

@ -34,10 +34,10 @@ achieve transparent mode.
### 1. Enable IP forwarding. ### 1. Enable IP forwarding.
{{< highlight bash >}} ```bash
sysctl -w net.ipv4.ip_forward=1 sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1 sysctl -w net.ipv6.conf.all.forwarding=1
{{< / highlight >}} ```
This makes sure that your machine forwards packets instead of rejecting them. This makes sure that your machine forwards packets instead of rejecting them.
@ -46,9 +46,9 @@ a newly created `/etc/sysctl.d/mitmproxy.conf` (see [here](https://superuser.com
### 2. Disable ICMP redirects. ### 2. Disable ICMP redirects.
{{< highlight bash >}} ```bash
sysctl -w net.ipv4.conf.all.send_redirects=0 sysctl -w net.ipv4.conf.all.send_redirects=0
{{< / highlight >}} ```
If your test device is on the same physical network, your machine shouldn't inform the device that If your test device is on the same physical network, your machine shouldn't inform the device that
there's a shorter route available by skipping the proxy. there's a shorter route available by skipping the proxy.
@ -60,12 +60,12 @@ If you want to persist this across reboots, see above.
Details will differ according to your setup, but the ruleset should look Details will differ according to your setup, but the ruleset should look
something like this: something like this:
{{< highlight bash >}} ```bash
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080 iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080 iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080 ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080 ip6tables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080
{{< / highlight >}} ```
If you want to persist this across reboots, you can use the `iptables-persistent` package (see If you want to persist this across reboots, you can use the `iptables-persistent` package (see
[here](http://www.microhowto.info/howto/make_the_configuration_of_iptables_persistent_on_debian.html)). [here](http://www.microhowto.info/howto/make_the_configuration_of_iptables_persistent_on_debian.html)).
@ -74,9 +74,9 @@ If you want to persist this across reboots, you can use the `iptables-persistent
You probably want a command like this: You probably want a command like this:
{{< highlight bash >}} ```bash
mitmproxy --mode transparent --showhost mitmproxy --mode transparent --showhost
{{< / highlight >}} ```
The `--mode transparent` option turns on transparent mode, and the `--showhost` argument tells The `--mode transparent` option turns on transparent mode, and the `--showhost` argument tells
mitmproxy to use the value of the Host header for URL display. mitmproxy to use the value of the Host header for URL display.
@ -92,24 +92,24 @@ Follow steps **1, 2** as above, but *instead* of the commands in step **3**, run
Create a user to run the mitmproxy Create a user to run the mitmproxy
{{< highlight bash >}} ```bash
sudo useradd --create-home mitmproxyuser sudo useradd --create-home mitmproxyuser
sudo -u mitmproxyuser bash -c 'cd ~ && pip install --user mitmproxy' sudo -u mitmproxyuser bash -c 'cd ~ && pip install --user mitmproxy'
{{< / highlight >}} ```
Then, configure the iptables rules to redirect all traffic from our local machine to mitmproxy. **Note**, as soon as you run these, you won't be able to perform successful network calls *until* you start mitmproxy. If you run into issues, `iptables -t nat -F` is a heavy handed way to flush (clear) *all* the rules from the iptables `nat` table (which includes any other rules you had configured). Then, configure the iptables rules to redirect all traffic from our local machine to mitmproxy. **Note**, as soon as you run these, you won't be able to perform successful network calls *until* you start mitmproxy. If you run into issues, `iptables -t nat -F` is a heavy handed way to flush (clear) *all* the rules from the iptables `nat` table (which includes any other rules you had configured).
{{< highlight bash >}} ```bash
iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 80 -j REDIRECT --to-port 8080 iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 443 -j REDIRECT --to-port 8080 iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 443 -j REDIRECT --to-port 8080
ip6tables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 80 -j REDIRECT --to-port 8080 ip6tables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 80 -j REDIRECT --to-port 8080
ip6tables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 443 -j REDIRECT --to-port 8080 ip6tables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner mitmproxyuser --dport 443 -j REDIRECT --to-port 8080
{{< / highlight >}} ```
This will redirect the packets from all users other than `mitmproxyuser` on the machine to mitmproxy. To avoid circularity, run mitmproxy as the user `mitmproxyuser`. Hence step **4** should look like: This will redirect the packets from all users other than `mitmproxyuser` on the machine to mitmproxy. To avoid circularity, run mitmproxy as the user `mitmproxyuser`. Hence step **4** should look like:
{{< highlight bash >}} ```bash
sudo -u mitmproxyuser bash -c '$HOME/.local/bin/mitmproxy --mode transparent --showhost --set block_global=false' sudo -u mitmproxyuser bash -c '$HOME/.local/bin/mitmproxy --mode transparent --showhost --set block_global=false'
{{< / highlight >}} ```
@ -117,16 +117,16 @@ sudo -u mitmproxyuser bash -c '$HOME/.local/bin/mitmproxy --mode transparent --s
### 1. Enable IP forwarding. ### 1. Enable IP forwarding.
{{< highlight bash >}} ```bash
sudo sysctl -w net.inet.ip.forwarding=1 sudo sysctl -w net.inet.ip.forwarding=1
{{< / highlight >}} ```
### 2. Place the following two lines in **/etc/pf.conf**. ### 2. Place the following two lines in **/etc/pf.conf**.
{{< highlight none >}} ```
mitm_if = "re2" mitm_if = "re2"
pass in quick proto tcp from $mitm_if to port { 80, 443 } divert-to 127.0.0.1 port 8080 pass in quick proto tcp from $mitm_if to port { 80, 443 } divert-to 127.0.0.1 port 8080
{{< / highlight >}} ```
These rules tell pf to divert all traffic from `$mitm_if` destined for port 80 These rules tell pf to divert all traffic from `$mitm_if` destined for port 80
or 443 to the local mitmproxy instance running on port 8080. You should replace or 443 to the local mitmproxy instance running on port 8080. You should replace
@ -134,23 +134,23 @@ or 443 to the local mitmproxy instance running on port 8080. You should replace
### 3. Configure pf with the rules. ### 3. Configure pf with the rules.
{{< highlight bash >}} ```bash
doas pfctl -f /etc/pf.conf doas pfctl -f /etc/pf.conf
{{< / highlight >}} ```
### 4. And now enable it. ### 4. And now enable it.
{{< highlight bash >}} ```bash
doas pfctl -e doas pfctl -e
{{< / highlight >}} ```
### 5. Fire up mitmproxy. ### 5. Fire up mitmproxy.
You probably want a command like this: You probably want a command like this:
{{< highlight bash >}} ```bash
mitmproxy --mode transparent --listen-host 127.0.0.1 --showhost mitmproxy --mode transparent --listen-host 127.0.0.1 --showhost
{{< / highlight >}} ```
The `--mode transparent` option turns on transparent mode, and the `--showhost` argument tells The `--mode transparent` option turns on transparent mode, and the `--showhost` argument tells
mitmproxy to use the value of the Host header for URL display. mitmproxy to use the value of the Host header for URL display.
@ -184,16 +184,16 @@ for earlier versions of OSX.
### 1. Enable IP forwarding. ### 1. Enable IP forwarding.
{{< highlight bash >}} ```bash
sudo sysctl -w net.inet.ip.forwarding=1 sudo sysctl -w net.inet.ip.forwarding=1
{{< / highlight >}} ```
### 2. Place the following line in a file called, say, **pf.conf**. ### 2. Place the following line in a file called, say, **pf.conf**.
{{< highlight none >}} ```
rdr pass on en0 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 8080 rdr pass on en0 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 8080
{{< / highlight >}} ```
This rule tells pf to redirect all traffic destined for port 80 or 443 This rule tells pf to redirect all traffic destined for port 80 or 443
to the local mitmproxy instance running on port 8080. You should replace to the local mitmproxy instance running on port 8080. You should replace
@ -201,24 +201,24 @@ to the local mitmproxy instance running on port 8080. You should replace
### 3. Configure pf with the rules. ### 3. Configure pf with the rules.
{{< highlight bash >}} ```bash
sudo pfctl -f pf.conf sudo pfctl -f pf.conf
{{< / highlight >}} ```
### 4. And now enable it. ### 4. And now enable it.
{{< highlight bash >}} ```bash
sudo pfctl -e sudo pfctl -e
{{< / highlight >}} ```
### 5. Configure sudoers to allow mitmproxy to access pfctl. ### 5. Configure sudoers to allow mitmproxy to access pfctl.
Edit the file **/etc/sudoers** on your system as root. Add the following line to Edit the file **/etc/sudoers** on your system as root. Add the following line to
the end of the file: the end of the file:
{{< highlight none >}} ```
ALL ALL=NOPASSWD: /sbin/pfctl -s state ALL ALL=NOPASSWD: /sbin/pfctl -s state
{{< / highlight >}} ```
Note that this allows any user on the system to run the command `/sbin/pfctl -s Note that this allows any user on the system to run the command `/sbin/pfctl -s
state` as root without a password. This only allows inspection of the state state` as root without a password. This only allows inspection of the state
@ -229,9 +229,9 @@ tighten the restriction up to the user running mitmproxy.
You probably want a command like this: You probably want a command like this:
{{< highlight bash >}} ```bash
mitmproxy --mode transparent --showhost mitmproxy --mode transparent --showhost
{{< / highlight >}} ```
The `--mode transparent` flag turns on transparent mode, and the `--showhost` argument tells The `--mode transparent` flag turns on transparent mode, and the `--showhost` argument tells
mitmproxy to use the value of the Host header for URL display. mitmproxy to use the value of the Host header for URL display.
@ -256,7 +256,7 @@ for more.
Follow steps **1, 2** as above, but in step **2** change the contents of the file **pf.conf** to Follow steps **1, 2** as above, but in step **2** change the contents of the file **pf.conf** to
{{< highlight none >}} ```
#The ports to redirect to proxy #The ports to redirect to proxy
redir_ports = "{http, https}" redir_ports = "{http, https}"
@ -274,13 +274,13 @@ tproxy_user = "nobody"
rdr pass proto tcp from any to any port $redir_ports -> $tproxy rdr pass proto tcp from any to any port $redir_ports -> $tproxy
pass out route-to (lo0 127.0.0.1) proto tcp from any to any port $redir_ports user { != $tproxy_user } pass out route-to (lo0 127.0.0.1) proto tcp from any to any port $redir_ports user { != $tproxy_user }
{{< / highlight >}} ```
Follow steps **3-5** above. This will redirect the packets from all users other than `nobody` on the machine to mitmproxy. To avoid circularity, run mitmproxy as the user `nobody`. Hence step **6** should look like: Follow steps **3-5** above. This will redirect the packets from all users other than `nobody` on the machine to mitmproxy. To avoid circularity, run mitmproxy as the user `nobody`. Hence step **6** should look like:
{{< highlight bash >}} ```bash
sudo -u nobody mitmproxy --mode transparent --showhost sudo -u nobody mitmproxy --mode transparent --showhost
{{< / highlight >}} ```
## "Full" transparent mode on Linux ## "Full" transparent mode on Linux
@ -289,7 +289,7 @@ connections. In case this isn't desired, the --spoof-source-address argument can
be used to use the client's IP address for server-side connections. The be used to use the client's IP address for server-side connections. The
following config is required for this mode to work: following config is required for this mode to work:
{{< highlight bash >}} ```bash
CLIENT_NET=192.168.1.0/24 CLIENT_NET=192.168.1.0/24
TABLE_ID=100 TABLE_ID=100
MARK=1 MARK=1
@ -303,15 +303,15 @@ iptables -t nat \
ip rule add fwmark $MARK lookup $TABLE_ID ip rule add fwmark $MARK lookup $TABLE_ID
ip route add local $CLIENT_NET dev lo table $TABLE_ID ip route add local $CLIENT_NET dev lo table $TABLE_ID
{{< / highlight >}} ```
This mode does require root privileges though. There's a wrapper in the examples This mode does require root privileges though. There's a wrapper in the examples
directory called 'mitmproxy_shim.c', which will enable you to use this mode with directory called 'mitmproxy_shim.c', which will enable you to use this mode with
dropped privileges. It can be used as follows: dropped privileges. It can be used as follows:
{{< highlight bash >}} ```bash
gcc examples/complex/full_transparency_shim.c -o mitmproxy_shim -lcap gcc examples/complex/full_transparency_shim.c -o mitmproxy_shim -lcap
sudo chown root:root mitmproxy_shim sudo chown root:root mitmproxy_shim
sudo chmod u+s mitmproxy_shim sudo chmod u+s mitmproxy_shim
./mitmproxy_shim $(which mitmproxy) --mode transparent --set spoof-source-address ./mitmproxy_shim $(which mitmproxy) --mode transparent --set spoof-source-address
{{< / highlight >}} ```

View File

@ -13,9 +13,9 @@ Wireshark can use these log files to decrypt packets. See the [Wireshark wiki](h
Key logging is enabled by setting the environment variable `SSLKEYLOGFILE` so Key logging is enabled by setting the environment variable `SSLKEYLOGFILE` so
that it points to a writable text file: that it points to a writable text file:
{{< highlight bash >}} ```bash
SSLKEYLOGFILE="$PWD/.mitmproxy/sslkeylogfile.txt" mitmproxy SSLKEYLOGFILE="$PWD/.mitmproxy/sslkeylogfile.txt" mitmproxy
{{< / highlight >}} ```
You can also `export` this environment variable to make it persistent for all applications started from your current shell session. You can also `export` this environment variable to make it persistent for all applications started from your current shell session.
You can specify the key file path in Wireshark via `Edit -> Preferences -> You can specify the key file path in Wireshark via `Edit -> Preferences ->

View File

@ -92,12 +92,12 @@ Re-route all GET requests from `example.org` to `mitmproxy.org` (using `|` as th
The `modify_body` option lets you specify an arbitrary number of patterns that The `modify_body` option lets you specify an arbitrary number of patterns that
define replacements within bodies of flows. `modify_body` patterns look like this: define replacements within bodies of flows. `modify_body` patterns look like this:
{{< highlight none >}} ```
/flow-filter/regex/replacement /flow-filter/regex/replacement
/flow-filter/regex/@file-path /flow-filter/regex/@file-path
/regex/replacement /regex/replacement
/regex/@file-path /regex/@file-path
{{< / highlight >}} ```
* **flow-filter** is an optional mitmproxy [filter expression]({{< relref "concepts-filters">}}) * **flow-filter** is an optional mitmproxy [filter expression]({{< relref "concepts-filters">}})
that defines which flows a replacement applies to. that defines which flows a replacement applies to.
@ -121,15 +121,15 @@ to create a script using the replacement API on Flow components.
Replace `foo` with `bar` in bodies of requests: Replace `foo` with `bar` in bodies of requests:
{{< highlight none >}} ```
/~q/foo/bar /~q/foo/bar
{{< / highlight >}} ```
Replace `foo` with the data read from `~/xss-exploit`: Replace `foo` with the data read from `~/xss-exploit`:
{{< highlight bash >}} ```bash
mitmdump --modify-body :~q:foo:@~/xss-exploit mitmdump --modify-body :~q:foo:@~/xss-exploit
{{< / highlight >}} ```
## Modify Headers ## Modify Headers
@ -138,12 +138,12 @@ The `modify_headers` option lets you specify a set of headers to be modified.
New headers can be added, and existing headers can be overwritten or removed. New headers can be added, and existing headers can be overwritten or removed.
`modify_headers` patterns look like this: `modify_headers` patterns look like this:
{{< highlight none >}} ```
/flow-filter/name/value /flow-filter/name/value
/flow-filter/name/@file-path /flow-filter/name/@file-path
/name/value /name/value
/name/@file-path /name/@file-path
{{< / highlight >}} ```
* **flow-filter** is an optional mitmproxy [filter expression]({{< relref "concepts-filters">}}) * **flow-filter** is an optional mitmproxy [filter expression]({{< relref "concepts-filters">}})
that defines which flows to modify headers on. that defines which flows to modify headers on.
@ -171,29 +171,29 @@ to create a script using the replacement API on Flow components.
Set the `Host` header to `example.org` for all requests (existing `Host` Set the `Host` header to `example.org` for all requests (existing `Host`
headers are replaced): headers are replaced):
{{< highlight none >}} ```
/~q/Host/example.org /~q/Host/example.org
{{< / highlight >}} ```
Set the `Host` header to `example.org` for all requests that do not have an Set the `Host` header to `example.org` for all requests that do not have an
existing `Host` header: existing `Host` header:
{{< highlight none >}} ```
/~q & !~h Host:/Host/example.org /~q & !~h Host:/Host/example.org
{{< / highlight >}} ```
Set the `User-Agent` header to the data read from `~/useragent.txt` for all requests Set the `User-Agent` header to the data read from `~/useragent.txt` for all requests
(existing `User-Agent` headers are replaced): (existing `User-Agent` headers are replaced):
{{< highlight none >}} ```
/~q/Host/@~/useragent.txt /~q/Host/@~/useragent.txt
{{< / highlight >}} ```
Remove existing `Host` headers from all requests: Remove existing `Host` headers from all requests:
{{< highlight none >}} ```
/~q/Host/ /~q/Host/
{{< / highlight >}} ```
## Proxy Authentication ## Proxy Authentication

View File

@ -15,9 +15,9 @@ Please follow the steps for your operating system.
The recommended way to install mitmproxy on macOS is to use The recommended way to install mitmproxy on macOS is to use
[Homebrew](https://brew.sh/): [Homebrew](https://brew.sh/):
{{< highlight bash >}} ```bash
brew install mitmproxy brew install mitmproxy
{{< / highlight >}} ```
Alternatively, you can download standalone binaries on [mitmproxy.org](https://mitmproxy.org/). Alternatively, you can download standalone binaries on [mitmproxy.org](https://mitmproxy.org/).

View File

@ -16,17 +16,17 @@ documentation.
### Example: Saving traffic ### Example: Saving traffic
{{< highlight bash >}} ```bash
mitmdump -w outfile mitmdump -w outfile
{{< / highlight >}} ```
Start up mitmdump in proxy mode, and write all traffic to **outfile**. Start up mitmdump in proxy mode, and write all traffic to **outfile**.
### Filtering saved traffic ### Filtering saved traffic
{{< highlight bash >}} ```bash
mitmdump -nr infile -w outfile "~m post" mitmdump -nr infile -w outfile "~m post"
{{< / highlight >}} ```
Start mitmdump without binding to the proxy port (`-n`), read all flows Start mitmdump without binding to the proxy port (`-n`), read all flows
from infile, apply the specified filter expression (only match POSTs), from infile, apply the specified filter expression (only match POSTs),
@ -34,36 +34,36 @@ and write to outfile.
### Client replay ### Client replay
{{< highlight bash >}} ```bash
mitmdump -nC outfile mitmdump -nC outfile
{{< / highlight >}} ```
Start mitmdump without binding to the proxy port (`-n`), then replay all Start mitmdump without binding to the proxy port (`-n`), then replay all
requests from outfile (`-C filename`). Flags combine in the obvious way, requests from outfile (`-C filename`). Flags combine in the obvious way,
so you can replay requests from one file, and write the resulting flows so you can replay requests from one file, and write the resulting flows
to another: to another:
{{< highlight bash >}} ```bash
mitmdump -nC srcfile -w dstfile mitmdump -nC srcfile -w dstfile
{{< / highlight >}} ```
See the [client-side replay]({{< relref "overview-features#client-side-replay" See the [client-side replay]({{< relref "overview-features#client-side-replay"
>}}) section for more information. >}}) section for more information.
### Running a script ### Running a script
{{< highlight bash >}} ```bash
mitmdump -s examples/simple/add_header.py mitmdump -s examples/simple/add_header.py
{{< / highlight >}} ```
This runs the **add_header.py** example script, which simply adds a new This runs the **add_header.py** example script, which simply adds a new
header to all responses. header to all responses.
### Scripted data transformation ### Scripted data transformation
{{< highlight bash >}} ```bash
mitmdump -ns examples/simple/add_header.py -r srcfile -w dstfile mitmdump -ns examples/simple/add_header.py -r srcfile -w dstfile
{{< / highlight >}} ```
This command loads flows from **srcfile**, transforms it according to This command loads flows from **srcfile**, transforms it according to
the specified script, then writes it back to **dstfile**. the specified script, then writes it back to **dstfile**.

View File

@ -25,9 +25,9 @@ how.
## 1. Run mitmdump to record our HTTP conversation to a file. ## 1. Run mitmdump to record our HTTP conversation to a file.
{{< highlight bash >}} ```bash
mitmdump -w wireless-login mitmdump -w wireless-login
{{< / highlight >}} ```
## 2. Point your browser at the mitmdump instance. ## 2. Point your browser at the mitmdump instance.
@ -41,9 +41,9 @@ your browser with mitmproxy's SSL certificate authority]({{< relref
And that's it\! You now have a serialised version of the login process And that's it\! You now have a serialised version of the login process
in the file wireless-login, and you can replay it at any time like this: in the file wireless-login, and you can replay it at any time like this:
{{< highlight bash >}} ```bash
mitmdump -C wireless-login mitmdump -C wireless-login
{{< / highlight >}} ```
## Embellishments ## Embellishments
@ -58,9 +58,9 @@ These add only a few moments to the time it takes to replay, but they're not
really needed and I somehow feel compelled to trim them anyway. So, we fire up really needed and I somehow feel compelled to trim them anyway. So, we fire up
the mitmproxy console tool on our serialised conversation, like so: the mitmproxy console tool on our serialised conversation, like so:
{{< highlight bash >}} ```bash
mitmproxy -r wireless-login mitmproxy -r wireless-login
{{< / highlight >}} ```
We can now go through and manually delete (using the <span We can now go through and manually delete (using the <span
data-role="kbd">d</span> keyboard shortcut) everything we want to trim. When data-role="kbd">d</span> keyboard shortcut) everything we want to trim. When

View File

@ -33,13 +33,13 @@ of leaderboards and so forth. Then, right at the end, there's a POST to
this tantalising this tantalising
URL: URL:
{{< highlight none >}} ```
https://service.gc.apple.com/WebObjects/GKGameStatsService.woa/wa/submitScore https://service.gc.apple.com/WebObjects/GKGameStatsService.woa/wa/submitScore
{{< / highlight >}} ```
The contents of the submission are particularly interesting: The contents of the submission are particularly interesting:
{{< highlight xml >}} ```xml
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>scores</key> <key>scores</key>
@ -57,7 +57,7 @@ The contents of the submission are particularly interesting:
</array> </array>
</dict> </dict>
</plist> </plist>
{{< / highlight >}} ```
This is a [property list](https://en.wikipedia.org/wiki/Property_list), This is a [property list](https://en.wikipedia.org/wiki/Property_list),
containing an identifier for the game, a score (55, in this case), and a containing an identifier for the game, a score (55, in this case), and a
@ -75,7 +75,7 @@ for raw body. Your preferred editor (taken from the EDITOR environment
variable) will now fire up. Lets bump the score up to something a bit variable) will now fire up. Lets bump the score up to something a bit
more ambitious: more ambitious:
{{< highlight xml >}} ```xml
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>scores</key> <key>scores</key>
@ -93,7 +93,7 @@ more ambitious:
</array> </array>
</dict> </dict>
</plist> </plist>
{{< / highlight >}} ```
Save the file and exit your editor. Save the file and exit your editor.