Setting signature in phpbb forum with cURL and Ruby script doesn't work

91 views Asked by At

I would like to set my forum signature in a phpbb forum, because it contains a coupon code and needs to be updated from time to time as the coupon expires, eg. once a month. So I want to achieve this automatically, for example with a cron job. I want to use cURL command line application and Ruby, because I am already familiar to them. However phpbb applies some security measuers called form creation_time and form_token to avoid automatic form submissions. They are created this way:

$now = time();
    $token_sid = ($user->data['user_id'] == ANONYMOUS && !empty($config['form_token_sid_guests'])) ? $user->session_id : '';
    $token = sha1($now . $user->data['user_form_salt'] . $form_name . $token_sid);

So creation_time represent the time as an integer value (Time.now.to_i in Ruby) and the form_token is a 40 character digest hash, which is a function of 4 variable: the mentioned time value, some kind of salt (it is taken from the phpbb database, and is set when user logs in first time), form name (ucp I think) and the PHP session id.

My code looks like follows:

#!/usr/bin/ruby

coupon_code=ARGV[0]

signature="For 20% discount, use this coupon code when buying from example.com: #{coupon_code}"

#getting a PHP session id, called sid from the login page before logging in
ret=%x{curl -c ~/example-com-cookie.txt 'http://www.example.com/ucp.php?mode=login' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://www.example.com/' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' --compressed -L}

matchdata=/\<input type\=\"hidden\" name\=\"sid\" value\=\"(.*?)\".*?\/\>/.match(ret.scrub)
if matchdata != nil then
 sid=matchdata[1]
else
 sid=""
end

puts sid

#login to the forum, and getting the cookie values, storing the in a cookie file (cookie jar)
ret=%x{curl 'http://www.example.com/ucp.php?mode=login&sid=#{sid}' -c ~/example-com-cookie.txt -H 'Origin: http://www.example.com' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http://www.example.com' -H 'Connection: keep-alive' --data 'username=myusername&password=mypassword&sid=#{sid}&redirect=index.php&login=Login' --compressed -L}

#getting form_token and creation_time hidden HTML field values
ret=%x{curl 'http://www.example.com/ucp.php?i=profile&mode=signature' -b  ~/example-com-cookie.txt -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://www.example.com/ucp.php?i=profile&mode=signature' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' --compressed -L}
matchdata=(/\<input type\=\"hidden\" name\=\"creation_time\" value\=\"(.*?)\".*?\/\>.*?\<input type\=\"hidden\" name\=\"form_token\" value\=\"(.*?)\".*?\/\>/m).match(ret.scrub)
puts matchdata.inspect

creation_time=matchdata[1]
#creation_time="1435022180"
form_token=matchdata[2]
#form_token="7f9d14cac39a5c5bcaf91682b3ff0410ea7ba6b8"#

puts creation_time
puts form_token

#modifying signature
ret=%x{curl 'http://www.example.com/ucp.php?i=profile&mode=signature' -b  ~/example-com-cookie.txt -H 'Origin: http://www.example.com' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Referer: http://www.example.com/ucp.php?i=profile&mode=signature' -H 'Connection: keep-alive' --data 'addbbcode20=100&signature=#{CGI.escape(signature)}&submit=Submit&creation_time=#{creation_time}&form_token=#{form_token}' --compressed -L}
matchdata=/\<span class\=\"genmed error\"\>(.*?)\<\/span\>/.match(ret.scrub)

if matchdata == nil then 
 puts "All OK!"
else
 puts matchdata[1]
end

I took the cURL lines form a real browser session made with Chrome, I simply copied the POST and GET requests from the developer console (Ctrl+Shift+I) with context menu "Copy as cURL" and then I made the necessary substitutions. Unfortunately my code doesn't work. I always get a HTML page containing the error message "Invalid Form".

However when I use the two commented lines when setting the creation_time and form_token variables (they originate from a real browser session, I simply copied them from the HTML source)

creation_time="1435022180"
form_token="7f9d14cac39a5c5bcaf91682b3ff0410ea7ba6b8"

my script works again even if I logout and login again from and into that real browser session! What's going on here?

2

There are 2 answers

0
vvondra On

phpBB3 checks the CSRF tokens for immediate requests following and assumes bots: https://github.com/phpbb/phpbb/blob/master/phpBB/includes/functions.php#L2102

0
Konstantin On

Okay, probled solved. I had to put a sleep time of at least 1 seconds between two consecutive cURL requests.