Cesium+ n'est pas attaqué :-)

Bonjour,

Sous ce titre racoleur, je viens vous faire part de mes réflexions concernant trois cas d’envoi de transactions à de mauvaises clefs pub (deux publics ici et ici, et un qui m’est arrivé).

Dans ces trois cas :

  • la transaction a été faite vers une clef publique qui, semble-t-il, n’appartient à personne.
  • cette clef publique est très similaire à la clef légitime, à l’exception d’un caractère.
  • les personnes ayant envoyé la monnaie ont trouvé ces mauvaises clefs par la recherche Cesium(+), et non par erreur de frappe. Ce comportement m’a fait tiquer. Je n’ai toujours pas d’explication.

On a donc eu Césium(+) qui a fourni aux utilisateurs des clefs « presque » justes. Je ne vois pas d’explication à cela, sauf une : une attaque a lieu grâce à CS+. J’ai vérifié, c’est faux. Cependant, je vais décrire cette attaque, qui est faisable, malgré un coût important.

Objectif de l’attaque

L’attaquant crée des pubkeys similaires à des pubkeys légitimes (comptes membres, comptes portefeuilles, comptes CS+) pour recevoir des versements par erreur.
Il s’appuie pour cela sur la fonction « recherche » de CS+, et sur deux faits :

  • Certains utilisateurs cherchent des comptes par les premiers caractères de la clef publique.
  • Césium affiche les 8 premiers caractères des compte sans profil CS+ de la même façon que des comptes avec profil. Ci-dessous, deux images, montrant un compte sans profil CS+, et avec. La différence est mince.

Description de l’attaque

  • l’attaquant récupère toutes les clefs publiques « légitimes », via un script comme g1-stats.
  • il fait un bruteforce sur l’ensemble des clefs publiques, non pas pour en trouver les accès, mais pour trouver des clefs publiques similaires, commençant par les mêmes 8 premiers caractères et différentes par un seul caractère. Le fait que cela soit fait sur un grand nombre de clefs permet certainement d’en trouver, je laisse les experts faire le calcul.
  • une fois ces clefs publiques similaires trouvées, il crée des profils CS+ dont le « titre » correspond aux 8 premiers caractères de la clef publique.
  • à partir de là, l’attaquant attend que des membres cherchent les comptes via CS+, et payent sur les mauvaises clefs publiques.

Est-ce en cours ?

Non.

J’ai écrit deux scripts:

  • l’un pour évaluer combien de « doubles comptes » existent sur la Blockchain (qu’ils aient été créés par erreur de frappe ou par l’attaque décrite)
  • l’autre pour regarder s’il existe des profils CS+ dont le titre correspond aux 8 premiers caractères d’une clef pub existante.

Je m’appuie dès le début sur une version corrigée de Ğ1Stats pour déterminer une liste de clefs publiques membres ou portefeuilles utilisés.

Résultats :

Il y a 26 comptes qui ont subi une ou des pertes de monnaie par transaction erronée. Je n’ai pas évalué les montants.

Il n’y a aucun profil CS+ « attaquant » tel que je l’ai décrit.

Il y a également 14 profils CS+ « légitimes » (sans double compte) qui utilisent les 8 premiers caractères de leur pubkey comme « titre ». Sans doute pour pouvoir être recherché en préservant un certain anonymat.

Voici les scripts, pour audit :

Double compte
#!/bin/bash

# result file
result="./double-wallets.result"
source="./all_wallets"

# declare lists
declare -a lst_begin
declare -a lst_many_wallets

# check for double accounts and fill lists
iter=0
for a in $(cat $source) ; do
    begina=${a:0:8}
    for b in $(cat $source) ; do
        beginb=${b:0:8}

        if [[ "$beginb" == "$begina" ]] && [[ "$a" != "$b" ]] ; then
            if [[ ! " ${lst_begin[@]} " =~ " ${begina} " ]]; then
                lst_begin+=($begina)
                echo "Begin : $begina"
                ((iter++))
            fi
            if [[ ! " ${lst_many_wallets[@]} " =~ " ${a} " ]]; then
                lst_many_wallets+=($a)
                echo "Pubkey : $a"
            fi
        fi
    done
done
echo "$iter"

CS+
#!/bin/bash
# this script will :
#  * extract the beginning of each pubkey
#  * search on a CS+ node for this beginning
#  * check that the answer matches the original pubkey.
#    * if not, print the original pubkey, the other, and the other's CS+ pseudonym

# parameters
result="./result"
CESIUM_POD="g1.data.e-is.pro"
source="./all_wallets"

len_list=$(cat $source | wc -l)
iter=0

# delete and re-create result
[[ -e $result ]] && rm $result
echo "Test if cesium+ is under attack" >> $result

# check for double accounts and fill lists
for a in $(cat $source) ; do
    # extract first 8 cheracters
    begin=${a:0:8}
#    begin=MATOGRAINE
    sleep 0.1
    # request CS+ for profiles with $begin as profile title
    cs_profile=$(curl -s "${CESIUM_POD}/user/profile/_search?filter_path=hits.hits&q=title:$begin")
    until cs_answer=$(echo "$cs_profile" | jq '.hits.hits[]' 2>/dev/null) ; do
        sleep 2
        cs_profile=$(curl -s "${CESIUM_POD}/user/profile/_search?filter_path=hits.hits&q=title:$begin")
    done
    # check if the answer's pubkey is different from the original pubkey, and display it if so.
    cs_id=$(echo "$cs_answer" | jq '._id' | sed 's/\"//g')
    if [[ "$a" != "$cs_id" ]]; then
        #check if the answer's title matches ~ the begin. If so, there might be an id usurpation : display
        cs_title=$(echo "$cs_answer" | jq '._source.title' | sed 's/\"//g')
        [[ "$cs_title" =~ "$begin" ]] && echo "########
Diff !
Begin  : $begin
Search : $a
Found  : $cs_id" >> $result
    else
        echo "SAME"
        echo "########
Same :
Begin  : $begin
Search : $a" >> $result
    fi

    # display progress
    clear
    echo
    echo "Scan en cours: $iter / $len_list"
    echo "$begin"
    cat $result

    ((iter++))
done

Comment éviter une telle attaque ?

Il s’agit ici surtout d’une question de design.

Une première piste a été évoquée ici : afficher systématiquement le checksum des clefs publiques. (peut-être pas lorsqu’il y en a un grand nombre, pour ne pas trop ralentir l’interface)

Une autre piste est possible : différencier l’interface si la clef publique est liée à un compte CS+ ou si elle ne l’est pas. Par exemple :

  • enlever le rond vide de l’image de profil
  • utiliser une couleur de fond différente

J’espère avoir été clair. Merci de votre attention !

7 J'aimes