2

How can I log in to a website using Bash in Linux?

For example, to log in to Stack Overflow I tried many different methods, shown below, but nothing's worked.

wget --save-cookies cookies.txt --keep-session-cookies --post-data="username=blahblah&password=blahblahblha" "https://stackoverflow.com/users/login?ssrc=head&returnurl=https%3a%2f%2fstackoverflow.com%2f"

or

curl --user myusername:mypassword https://stackoverflow.com/users/login?ssrc=head&returnurl=https%3a%2f%2fstackoverflow.com%2f -v

I tried to inspect the element using Chrome to copy the curl request, but it didn't work (maybe it depends on a cookie and is only valid for a certain period of time).

Note that I need to login with username and password not with a cookie.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Majid Hajibaba
  • 3,105
  • 6
  • 23
  • 55
  • With resepct to `curl` does your password contain any special characters? If so try wrapping the password around single quotes. – TenG Jun 26 '21 at 19:24
  • No the password is just characters! – Majid Hajibaba Jun 27 '21 at 06:39
  • 2
    What tells you it didn't work? HTTP error code? Note that those commands don't automatically handle cookies as a browser would ; in your `wget` command you save cookies to a cookies.txt file, which is good, but you also need to refer to this file in further requests (and I don't see any cookie handling in the curl command) – Aaron Jun 29 '21 at 09:51
  • I just need to be login and see my stats (in SO), just like when click on login in the web page. I don't need to use cookie. – Majid Hajibaba Jun 29 '21 at 12:34
  • You do actually, HTTP is stateless and the server processing your stats requests has no way to tell you're the same guy that logged in seconds (or weeks) ago, unless you provide it with a token it gave you when you authenticated. That's the cookie. (if you look at the auth request's response, I believe it's the `set-cookie: acct=...` header that matters for SO. At least when I deleted the `acct` cookie from my browser I had to log in again) – Aaron Jun 29 '21 at 13:48
  • Can you login to your SO account with wget or curl! If yes please send it to me to test it. I test and result is 'enter your password' in login page – Majid Hajibaba Jun 29 '21 at 14:46
  • `curl -c cookies -X POST -F 'email=yourmail@provider.dn' -F 'password=yourpwd' https://stackoverflow.com/users/login` somewhat seems to work : once executed, the `cookies` file will contain an entry for the `acct` cookie. That said it seems like it wasn't enough to access the authenticated version of the website – Aaron Jun 29 '21 at 21:01
  • 1
    What's final goal? Which information are you searching for? – F. Hauri - Give Up GitHub Jul 01 '21 at 18:18
  • You mentioned in one of your comments about "to see your stats in SO" which is a different task (i think) and not stated in your question. For such a task, you may not need to login (depending on what stats you want to see). – Ahmet Said Akbulut Jul 02 '21 at 08:59
  • Aaron. I test it and not worked for me. – Majid Hajibaba Jul 03 '21 at 06:34

2 Answers2

9

For fun only: Connection: keep-alive in bash.

Introduction

My goal was to build a Bash environment where the current console (or script) could deal interactively with an authenticated HTTPS session. This could be used to address lot of IoT targets, address any provider platform to monitor personal account, etc.

Unfortunately, this could be badly used for stressing or hacking web platforms (targeting anyone) or even to targeting Stack Overflow's Fanatic badge (dirty cheater!).

My apologies for any bad use of this. Anyway, I'm not responsible of what people do.

Near pure Bash: require only OpenSSL:

... and gpg, but you're free to store your credential in another way.

Preparing some values:

#!/bin/bash
shopt -s extglob

URL='https://stackoverflow.com/'
IFS=: read  -r user pass < <(gpg -qd <socred.gpg)

IFS=/ read -r _ _ hst _ <<<"$URL"

Running the OpenSSL executable as a background task:

exec {wwwE}<> <(: - O)
exec {wwwI}<> <(: - b)
exec {wwwO}< <(
  exec stdbuf -o0 openssl s_client -quiet -connect "$hst":443 <&$wwwI 2>&$wwwE)
osslpid=$!

Then now, there is a little doReq function to create two variables: $cookie and $htstatus, and three arrays: $hthead, $htbody and $hterr:

doReq() {
    hthead=() htbody=() hterr=()
    local target=$1 method=${2:-GET} head=true line cookies
    printf >&$wwwI '%s\r\n' "$method $target HTTP/1.1" "Host: $hst" \
           "User-Agent: aobs/0.01" "Connection: keep-alive" "Accept: */*"
    [ "$cookie" ] && printf >&$wwwI '%s' "$cookie"
    if [ "$method" = "POST" ];then
        printf >&$wwwI '%s\r\n%s\r\n\r\n%s' "Content-Length: ${#3}" \
                       'Content-Type: application/x-www-form-urlencoded' "$3"
    else printf >&$wwwI '\r\n'
    fi
    read -t 10 -ru $wwwO line
    htstatus=${line%$'\r'} ; hthead=("$htstatus")
    while read -t .3 -ru $wwwO line;do
        [ "${line%$'\r'}" ] || head=false;
        if $head ;then
            hthead+=("${line%$'\r'}");
            case $line in
                [sS]et-[cC]ookie:* ) line=${line#*: };
                                 cookies+=("${line%%;*}");;
            esac
        else htbody+=("${line%$'\r'}") ;fi
    done
    if read -t 0 -ru $wwwE;then
        while read -t .1 -ru $wwwE line;do
            hterr+=("${line%$'\r'}")
            case $line in
                depth* | verify* ) ;;
                * ) echo "ERR: $line" ;;
    esac ; done ; fi
    [ ! -v "cookie" ] && [ "${cookies[0]}" ] &&
        printf -v cookie 'Cookie: %s\r\n' "${cookies[@]}"
}

Usage: doReq /file_part_of_URL [method] [post datas]

Let's login:

doReq /users/login POST "email=$user&password=$pass"

Now show my badges:

doReq /
for ((i=${#htbody[@]};i--;)) ;do
    line="${htbody[i]}"
    case $line in
        *badge1* ) line="${htbody[i-1]}${htbody[i]}${htbody[i+1]}"
                   line=${line//>+([0-9])</><} line=${line//<*([^>])>}
                   printf '%b\n' "${line//&#9679;/ \\U25cf }" ;;
esac ; done

On my desk, with my account, this prints:

 ● 13 gold badges ● 88 silver badges ● 112 bronze badges

(just now).

Of course, you're now ready to run doReq any time you like, as the connection stays open. We are now in environment/condition cited in the Introduction. (The version on my site does a forever loop, requesting this in a more efficient way, each rounded two minutes (EPOCHSECONDS % 120), up to user interaction. See at the bottom of this.)

...

Once you're done, before exit, you could stop openssl and close your file descriptor:

(I've added ls and ps as debug commands.)

ls -l /dev/fd/ ; ps --tty $(tty) ufw
kill $osslpid
exec {wwwE}<&-
exec {wwwI}>&-
exec {wwwO}<&-
ls -l /dev/fd/ ; ps --tty $(tty) ufw

This shows:

total 0
lrwx------ 1 user user 64 jui  2 13:52 0 -> /dev/pts/2
l-wx------ 1 user user 64 jui  2 13:52 1 -> /dev/pts/2
lrwx------ 1 user user 64 jui  2 13:52 10 -> pipe:[940266653]
lrwx------ 1 user user 64 jui  2 13:52 11 -> pipe:[940266654]
lr-x------ 1 user user 64 jui  2 13:52 12 -> pipe:[940266655]
lrwx------ 1 user user 64 jui  2 13:52 2 -> /dev/pts/2
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user    28110  0.0  0.0  11812  7144 pts/7    Ss   jui01   0:02 bash
user    14038 30.0  0.0   9116  4228 pts/7    S+   13:52   0:00  \_ /bin/bash ./getSo.sh
user    14045  0.5  0.0   9356  5856 pts/7    S+   13:52   0:00       \_ openssl s_client -quiet -connect stackoverflow.com:443
user    14048  0.0  0.0  12404  3400 pts/7    R+   13:52   0:00       \_ ps --tty /dev/pts/7 ufw

total 0
lrwx------ 1 user user 64 jui  2 13:52 0 -> /dev/pts/2
l-wx------ 1 user user 64 jui  2 13:52 1 -> /dev/pts/2
lrwx------ 1 user user 64 jui  2 13:52 2 -> /dev/pts/2
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user    28110  0.0  0.0  11812  7144 pts/7    Ss   jui01   0:02 bash
user    14038 30.0  0.0   9632  4756 pts/7    S+   13:52   0:00  \_ /bin/bash ./getSo.sh
user    14051  0.0  0.0  12404  3332 pts/7    R+   13:52   0:00      \_ ps --tty /dev/pts/7 ufw

The OpenSSL process is done and all three file descriptors become closed.

You could find this script (less condensed), with an extended main loop at getSo.sh.txt, getSo.sh.

2022-09-29 Edit getSo.sh replacing badge1 by badge3. (Script work only if you already earnned at least one bronze badge!! This is a bug, but harmless than previous version which require a gold badge.)

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • Hauri. If I was a dirty cheater, I could use Windows scheduler to do that. I just challenge myself to learn new methods and your script tech me new methods. – Majid Hajibaba Jul 03 '21 at 08:49
  • 1
    Sorry, I won't hurt you! I'm cool with that: I'm for freedom, for everyone! *( Just matter with our self conscience ;-)* – F. Hauri - Give Up GitHub Jul 03 '21 at 08:53
  • Thank you. I know that Hauri, However I cannot do the script with encrypted credential and have to hardcode user and pass. However, your method was complete and the only way which is worked for my requirement. – Majid Hajibaba Jul 03 '21 at 09:00
  • Would you be so kind and elaborate this magic? `exec {wwwE}<> <(: - O)`, more especially what the use is of `: - O`? – kvantour Jul 05 '21 at 10:09
  • 1
    @kvantour Just a kind of smiley `:p)` Explanation `:` is an alias of `true` command wich accept any number of parameter and return alway *`true`*. `-` and `O` are useless arguments.... My post begin by **For fun only!** – F. Hauri - Give Up GitHub Jul 05 '21 at 11:52
  • 1
    @kvantour And `exec {wwwE}<>` open a bi-directional *file descriptor* pointing to a *unnamed fifo* to the `<()` output of the command `:` (`true`)... Then `exec {wwwE}<&-` will close *file descriptor* (and free the *unnamed fifo*) – F. Hauri - Give Up GitHub Jul 05 '21 at 11:53
  • 1
    @F.Hauri Thanks, Those smileys really puzzled me. I was already wondering if this was a special feature of bash I was not ware of. Good one! – kvantour Jul 05 '21 at 12:36
  • Just updated the [getSo.sh script on my site](https://f-hauri.ch/vrac/getSo.sh.txt). correct bug reconnecting immediatly if connection fail.Added `notify-send` to prompt change on my desktop – F. Hauri - Give Up GitHub Mar 25 '22 at 07:17
  • 2
    this is insane. no sane person would solve it in bash. kinda cool tho – hanshenrik Mar 25 '22 at 12:28
  • @hanshenrik If you liked this, have a look at [*My two cents* about Is bash a programming language?](https://stackoverflow.com/a/67498861/1765658) – F. Hauri - Give Up GitHub Sep 29 '22 at 14:15
1

It fully depends on the target website, but for example for Stack Overflow you can use the commands below:

curl -X POST "https://stackoverflow.com/users/login" -H "Content-Type: application/x-www-form-urlencoded" -d "email=user@email.com" -d "password=password" -c cookie.txt

# Verify your login
curl -b cookie.txt https://stackoverflow.com | grep YOUR_NAME
# OR check the status code from edit profile that should be 200 OK
curl -b cookie.txt https://stackoverflow.com/users/edit/YOUR_USER_ID -i 2>/dev/null
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Seena Fallah
  • 560
  • 4
  • 12