Grinnode-live / 2020-grin-bug-bash-challenge

Finding bugs in Grin-Wallet & Grin-nodes for a bounty prior to Grin fork v5.
3 stars 1 forks source link

grin-wallet uses .api_secret when talking to grin node /v2/foreign #15

Closed bladedoyle closed 3 years ago

bladedoyle commented 3 years ago

start with clean ubuntu 20:

cd ~

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.bashrc

sudo bash -c "set -ex && apt-get update && apt-get --no-install-recommends --yes install clang libclang-dev llvm-dev libncurses5 libncursesw5 cmake git locales libssl-dev pkg-config"

git clone https://github.com/mimblewimble/grin.git
cd grin
git checkout v5.0.0-beta.2
cargo build

./target/debug/grin

(Let that run, start a new shell)

cd ~
git clone https://github.com/mimblewimble/grin-wallet.git
cd grin-wallet
git checkout v5.0.0-beta.2
cargo build

(wait for node to finish syncing)

./target/debug/grin-wallet init


cat ~/.grin/main/.api_secret AU5zX2eBCSaBaXzJ7b3r cat ~/.grin/main/.foreign_api_secret 5G5stpjgh9E3vUDVJydc

Verify that the nodes /v2/foreign API is working and that its checking the secret curl -i -XPOST -ugrin:XXX -d "{ \"method\": \"get_tip\", \"params\": [], \"jsonrpc\": \"2.0\", \"id\": 11 }" http://localhost:3413/v2/foreign

That should fail with "HTTP/1.1 401 Unauthorized".

Verify that the nodes /v2/foreign API is checking against the .foreign_api_secret curl -i -XPOST -ugrin:$(cat ~/.grin/main/.foreign_api_secret) -d "{ \"method\": \"get_tip\", \"params\": [], \"jsonrpc\": \"2.0\", \"id\": 11 }" http://localhost:3413/v2/foreign

That should succeed with "HTTP/1.1 200 OK" and return some data. Make note: the nodes /v2/foreign API is checking against the .foreign_api_secret

Check if the wallet works:

in a 3rd shell - start a tcpdump watching for calls to the nodes port 3413 sudo tcpdump -i lo -s 0 -A 'tcp dst port 3413 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x3C21444F'

back in shell 2 ~/grin-wallet/target/debug/grin-wallet info (entry wallet password)

See that the wallet fails to contact the node - not just for get_version but also for get_tip:

20201213 03:42:08.895 ERROR grin_wallet_impls::node_clients::http - Error calling get_version: ResponseError error: Cannot parse response
20201213 03:42:08.895 ERROR grin_wallet_impls::node_clients::http - Unable to contact Node to get version info: Client Callback Error: Error calling get_version: ResponseError error: Cannot parse response
Password: 
20201213 03:42:15.758 ERROR grin_wallet_impls::node_clients::http - Error calling get_tip: ResponseError error: Cannot parse response
20201213 03:42:15.759 WARN grin_wallet_libwallet::api_impl::owner_updater - Updater Thread unable to contact node

____ Wallet Summary Info - Account 'default' as of height 0 ____

 Confirmed Total                  | 0.000000000 
 Awaiting Confirmation (< 10)     | 0.000000000 
 Awaiting Finalization            | 0.000000000 
 Locked by previous transaction   | 0.000000000 
 -------------------------------- | ------------- 
 Currently Spendable              | 0.000000000 

WARNING: Wallet failed to verify data against a live chain. The above is from local cache and only valid up to the given height! (is your `grin server` offline or broken?)
Command 'info' completed successfully

So, the wallet can not talk to the node even with default configuration with both grin and grin-wallet on the same host.

Whats going on?

Check the tcpdump output - what auth was sent from the wallet to the node?

The tcpdump will have an output like this:

03:42:08.893960 IP localhost.56448 > localhost.3413: Flags [P.], seq 968190909:968191122, ack 141553877, win 512, options [nop,nop,TS val 3707947292 ecr 3707947291], length 213
E.. M.@.@..>...........U9.k..o.............
........**POST /v2/foreign** HTTP/1.1
**authorization: Basic Z3JpbjpBVTV6WDJlQkNTYUJhWHpKN2Izcg==**
user-agent: grin-client
accept: application/json
content-type: application/json
host: 127.0.0.1:3413
content-length: 61

03:42:08.894351 IP localhost.3413 > localhost.56448: Flags [P.], seq 1:132, ack 274, win 512, options [nop,nop,TS val 3707947292 ecr 3707947292], length 131
E...1j@.@.
..........U...o..9.l............
........HTTP/1.1 **401 Unauthorized**
www-authenticate: Basic realm=GrinForeignAPI
content-length: 0
date: Sun, 13 Dec 2020 03:42:08 GMT

see the line with "authorization: Basic Z3JpbjpBVTV6WDJlQkNTYUJhWHpKN2Izcg==" decode the baicauth to see what password was used:

echo Z3JpbjpBVTV6WDJlQkNTYUJhWHpKN2Izcg== | base64 -d grin:AU5zX2eBCSaBaXzJ7b3r

this is the ~/.grin/main/.api_secret. The wallet is sending the .api_secret to the nodes /v2/foreign API. But as we saw above, the node is using ~/.grin/main/.foreign_api_secret

Include the output of command

grin-wallet -V

and your environment

uname -a
MCM-Mike commented 3 years ago

made small formatting changes.

bladedoyle commented 3 years ago

This is confirmed fixed in rc1

goyle commented 3 years ago

Note: As per @bladedoyle's comment, this is confirmed fixed in rc1. I will test to see if I can reproduce the fix.

Environment

OS: Debian 10\ Grin Node: grin 5.0.0-rc.2 \ Grin Wallet: grin-wallet 5.0.0-rc.1 \ System Info: Linux debian3 4.19.0-13-amd64 #1 SMP Debian 4.19.160-2 (2020-11-28) x86_64 GNU/Linux

Steps

0: Building the node and wallet

See here for the full steps for building GRIN-Node v5.0.0-rc.2. 1. Download GRIN-Node v5.0.0-rc.2. ```shell $ wget https://github.com/mimblewimble/grin/archive/v5.0.0-rc.2.tar.gz ``` 1. Extract `v5.0.0-rc.2.tar.gz`. ```shell $ tar -xvf v5.0.0-rc.2.tar.gz ``` * Output should be as follows. ``` grin-5.0.0-rc.2/ grin-5.0.0-rc.2/.cargo/ grin-5.0.0-rc.2/.cargo/config grin-5.0.0-rc.2/.ci/ grin-5.0.0-rc.2/.ci/general-jobs grin-5.0.0-rc.2/.ci/release.yml grin-5.0.0-rc.2/.ci/test.yml grin-5.0.0-rc.2/.ci/windows-release.yml grin-5.0.0-rc.2/.editorconfig grin-5.0.0-rc.2/.github/ ... ``` 1. Install Rust. ```shell $ curl https://sh.rustup.rs -sSf | sh; source $HOME/.cargo/env ``` * Proceed with installation with default profile. ``` default host triple: x86_64-unknown-linux-gnu default toolchain: stable (default) profile: default modify PATH variable: yes ``` * Output should be as follows. ``` stable-x86_64-unknown-linux-gnu installed - rustc 1.48.0 (7eac88abb 2020-11-16) ``` 1. Download dependencies, including `libcursesw5`. ```shell # apt install build-essential git tor cmake git libgit2-dev clang libncursesw5 libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config libssl-dev llvm ``` 1. Build GRIN-Node v5.0.0-rc.2. ```shell $ cd grin-5.0.0-rc.2/ $ cargo build --release ``` 1. Start node. ``` $ ./grin ``` 1. Wait until Grin has fully synced. 1. Success!
See here for the full steps for building GRIN-Wallet v5.0.0-rc.1. 1. Download GRIN-Wallet v5.0.0-rc.1. ```shell $ wget https://github.com/mimblewimble/grin-wallet/archive/v5.0.0-rc.1.tar.gz ``` 1. Extract `v5.0.0-rc.1.tar.gz`. ```shell $ tar -xvf v5.0.0-rc.1.tar.gz ``` * Output should be as follows. ``` grin-wallet-5.0.0-rc.1/ grin-wallet-5.0.0-rc.1/.cargo/ grin-wallet-5.0.0-rc.1/.cargo/config grin-wallet-5.0.0-rc.1/.ci/ grin-wallet-5.0.0-rc.1/.ci/general-jobs grin-wallet-5.0.0-rc.1/.ci/release.yml grin-wallet-5.0.0-rc.1/.ci/test.yml grin-wallet-5.0.0-rc.1/.ci/windows-release.yml grin-wallet-5.0.0-rc.1/.github/ ... ``` 1. Install Rust. ```shell $ curl https://sh.rustup.rs -sSf | sh; source $HOME/.cargo/env ``` * Proceed with installation with default profile. ``` default host triple: x86_64-unknown-linux-gnu default toolchain: stable (default) profile: default modify PATH variable: yes ``` * Output should be as follows. ``` stable-x86_64-unknown-linux-gnu installed - rustc 1.48.0 (7eac88abb 2020-11-16) ``` 1. Download dependencies, including `libcursesw5`. ```shell # apt install build-essential git tor cmake git libgit2-dev clang libncursesw5 libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config libssl-dev llvm ``` 1. Build GRIN-Wallet v5.0.0-rc.1. ```shell $ cd grin-wallet-5.0.0-rc.1/ $ cargo build --release ``` 1. Wait for the GRIN-Wallet to finish compiling and then check the wallet version. ```shell $ cd target/release $ ./grin-wallet -V ``` * The output should be as follows. ``` grin-wallet 5.0.0-rc.1 ``` 1. Success!

1: Verify the Node Foreign API

  1. Verify that the nodes /v2/foreign API is working and that it is checking the secret. Supply "XXX" as the foreign API password. It should fail with "HTTP/1.1 401 Unauthorized".
    $ curl -i -XPOST -ugrin:XXX -d "{ \"method\": \"get_tip\", \"params\": [], \"jsonrpc\": \"2.0\", \"id\": 11 }" http://localhost:3413/v2/foreign

    Output:

    HTTP/1.1 401 Unauthorized
    www-authenticate: Basic realm=GrinForeignAPI
    content-length: 0
    date: Sat, 02 Jan 2021 04:05:15 GMT
  2. Verify the foreign API again but with the correct API password using .foreign_api_secret. It should succeed with "HTTP/1.1 200 OK".

    $ curl -i -XPOST -ugrin:$(cat ~/.grin/main/.foreign_api_secret) -d "{ \"method\": \"get_tip\", \"params\": [], \"jsonrpc\": \"2.0\", \"id\": 11 }" http://localhost:3413/v2/foreign

    Output:

    HTTP/1.1 200 OK
    access-control-allow-origin: *
    access-control-allow-headers: Content-Type, Authorization
    content-type: application/json
    content-length: 330
    date: Sat, 02 Jan 2021 04:07:39 GMT
    
    {
        "id": 11,
        "jsonrpc": "2.0",
        "result": {
            "Ok": {
            "height": 1028537,
            "last_block_pushed": "0001c84535e900c591a856f2cd5e274281a7990175dfdfa00b0b6ed552e020f9",
            "prev_block_to_last": "00001e506ab1ccc68f4ed3b4e8dcdf4a08285d751a2e6fa1b9317d59d4816d22",
            "total_difficulty": 1739280652504775
            }
        }
    }

2: Contacting the node using the wallet

  1. Open up a new terminal and start a tcpdump watching for calls to port 3413.
    # sudo tcpdump -i lo -s 0 -A 'tcp dst port 3413 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450 or tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x3C21444F'

    Output:

    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
    ...
  2. While tcpdump is running, open a new terminal and run GRIN-Wallet.

    $ ./grin-wallet info

    Output:

    20210102 04:15:08.163 INFO grin_util::logger - log4rs is initialized, file level: Debug, stdout level: Debug, min. level: Debug
    20210102 04:15:08.163 INFO grin_wallet - Using wallet configuration file at /home/user3/.grin/main/grin-wallet.toml
    20210102 04:15:08.163 INFO grin_wallet - This is Grin Wallet version 5.0.0-rc.1, built for x86_64-unknown-linux-gnu by rustc 1.48.0 (7eac88abb 2020-11-16).
    20210102 04:15:08.163 DEBUG grin_wallet - Built with profile "release", features "".
    Password: 
    20210102 04:15:13.951 DEBUG grin_store::lmdb - DB Mapsize for /home/user3/.grin/main/wallet_data/db/lmdb is 134217728
    20210102 04:15:13.957 DEBUG grin_wallet_impls::lifecycle::seed - Using wallet seed file at: /home/user3/.grin/main/wallet_data/wallet.seed
    20210102 04:15:13.986 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Updating outputs from node
    20210102 04:15:13.991 DEBUG grin_wallet_libwallet::internal::updater - Refreshing wallet outputs
    20210102 04:15:13.999 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Updating transactions
    20210102 04:15:14.008 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Starting UTXO scan
    20210102 04:15:14.008 WARN grin_wallet_libwallet::api_impl::owner_updater - Scanning - 0% complete
    20210102 04:15:14.141 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Checking 1000 outputs, up to index 9004157. (Highest index: 9003970)
    20210102 04:15:14.141 WARN grin_wallet_libwallet::api_impl::owner_updater - Scanning - 93% complete
    20210102 04:15:14.190 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Checking 76 outputs, up to index 9004157. (Highest index: 9004157)
    20210102 04:15:14.190 WARN grin_wallet_libwallet::api_impl::owner_updater - Scanning - 99% complete
    20210102 04:15:14.193 DEBUG grin_wallet_libwallet::api_impl::owner_updater - Identified 0 wallet_outputs as belonging to this wallet
    20210102 04:15:14.193 WARN grin_wallet_libwallet::api_impl::owner_updater - Scanning - 99% complete
    20210102 04:15:14.194 WARN grin_wallet_libwallet::api_impl::owner_updater - Scanning Complete
    
    ____ Wallet Summary Info - Account 'default' as of height 1028549 ____
    
    Confirmed Total                  | 5.000000000 
    Awaiting Confirmation (< 10)     | 0.000000000 
    Awaiting Finalization            | 0.000000000 
    Locked by previous transaction   | 0.000000000 
    -------------------------------- | ------------- 
    Currently Spendable              | 5.000000000 
    
    Command 'info' completed successfully
  3. Check the tcpdump after opening the GRIN-Wallet.

    Cropped output:

    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
    04:18:22.461509 IP localhost.57128 > localhost.3413: Flags [P.], seq 2630715715:2630715928, ack 3994877459, win 512, options [nop,nop,TS val 650970768 ecr 650970768], length 213
    E.. pj@.@............(.U...C...............
    &...&...POST /v2/foreign HTTP/1.1
    authorization: Basic Z3JpbjoxQWJLTHVXZ0toRXA2aERVdVZFVg==
    user-agent: grin-client
    accept: application/json
    content-type: application/json
    host: 127.0.0.1:3413
    content-length: 61
    
    04:18:22.461698 IP localhost.3413 > localhost.57128: Flags [P.], seq 1:339, ack 274, win 512, options [nop,nop,TS val 650970769 ecr 650970769], length 338
    E....r@.@............U.(.......U.....z.....
    &...&...HTTP/1.1 200 OK
    access-control-allow-origin: *
    access-control-allow-headers: Content-Type, Authorization
    content-type: application/json
    content-length: 138
    date: Sat, 02 Jan 2021 04:18:22 GMT
    
    {
    "id": 1,
    "jsonrpc": "2.0",
    "result": {
        "Ok": {
        "block_header_version": 4,
        "node_version": "5.0.0-rc.2"
        }
    }
    }
    04:18:26.480097 IP localhost.57130 > localhost.3413: Flags [P.], seq 1062219030:1062219243, ack 113109172, win 512, options [nop,nop,TS val 650974787 ecr 650974785], length 213
    E.. ..@.@..0.........*.U?P-................
    &..C&..APOST /v2/foreign HTTP/1.1
    authorization: Basic Z3JpbjoxQWJLTHVXZ0toRXA2aERVdVZFVg==
    user-agent: grin-client
    accept: application/json
    content-type: application/json
    host: 127.0.0.1:3413
    content-length: 57
    
    04:18:26.480273 IP localhost.3413 > localhost.57130: Flags [P.], seq 1:530, ack 270, win 512, options [nop,nop,TS val 650974787 ecr 650974787], length 529
    E..E..@.@.)..........U.*....?P.$.....:.....
    &..C&..CHTTP/1.1 200 OK
    access-control-allow-origin: *
    access-control-allow-headers: Content-Type, Authorization
    content-type: application/json
    content-length: 329
    date: Sat, 02 Jan 2021 04:18:26 GMT
    
    {
    "id": 1,
    "jsonrpc": "2.0",
    "result": {
        "Ok": {
        "height": 1028554,
        "last_block_pushed": "000251792189a2ead4f5c514d517c304217ac1622d67e979d1fd6120f19d8059",
        "prev_block_to_last": "000220cd87d97776a8148b07be8c9e0a980a08dc12566ff878da87c249ccf6e7",
        "total_difficulty": 1739284091740767
        }
    }
    }
    
    ...
    ...
  4. The tcpdump has the line similar to "authorization: Basic Z3JpbjoxQWJLTHVXZ0toRXA2aERVdVZFVg==". This can be decoded.

    Decode using your own data!

    $ echo Z3JpbjoxQWJLTHVXZ0toRXA2aERVdVZFVg== | base64 -d

    My output:

    grin:1AbKLuWgKhEp6hDUuVEV
  5. Compare the decoded output with your .api_secret and .foreign_api_secret.
    $ cat ~/.grin/main/.api_secret

    My output:

    z3KB0GMAEkCb7JTXMCyc

    $ cat ~/.grin/main/.foreign_api_secret

    My output:

    1AbKLuWgKhEp6hDUuVEV
  6. Record which secret the decoded output matches.

Final Results

The authorization code found in my tcpdump.

authorization: Basic Z3JpbjoxQWJLTHVXZ0toRXA2aERVdVZFVg==

Decoded authorization code:

grin:1AbKLuWgKhEp6hDUuVEV

The code matches the .foreign_api_secret:

1AbKLuWgKhEp6hDUuVEV

Conclusion

Following @bladedoyle's steps, I was able to confirm that the bug has been fixed as of GRIN-Node v5.0.0-rc.2 and GRIN-Wallet v5.0.0-rc.1 version. Based on my findings with the new GRIN releases, the output matches the .foreign_api_secret now and not the .api_secret like before. The wallet talks to the node correctly.

marekyggdrasil commented 3 years ago

Thanks for checking that, @goyle !