PHP cookie-bases session swapping in phorum - php

I'm experiencing a strange error in my phorum server - seemingly at random, some users will be swapped with each other, and find themselves fully logged in as one another, with complete access to one another's accounts. I've experienced this bug myself once but cannot recreate it.
Phorum is configured to track sessions via cookie, with the session hashes also stored in the user database. I've confirmed the database is intact and there aren't session ID collisions happening.
You can see the source for phorum's authentication and session management here, it's fairly straightforward. Sessions are only created via log-in or from existing cookies so my working theory (after talking to a phorum developer) is that there is some sort of caching issue on the server. There's a known caching issue that affects ASP (see here or here for examples) but my server is a Linux server running Apache 2.4, MySQL (technically MariaDB 10.1 + InnoDB) and PHP 5.6. Is anyone aware of how this might be happening? I've been plugging away at this for over a week and have made little progress other than confirming the lack of bugs in the phorum session code.
The only clue I have to go on is that the session swapping started on the same day my hosting service took down (and restored) their file servers. They said they don't see how that could be responsible, however.
EDIT #1: I am adding some request and response headers.
Here is the response for an initial GET to get a list of forums.
General
Request URL: https://www.example.com/forum/list.php?11 Request
Method: GET Status Code: 200 Remote Address: x.x.x.x:443
Referrer Policy: no-referrer-when-downgrade
Response Headers
content-encoding: gzip content-type: text/html;
charset=UTF-8 date: Mon, 07 May 2018 20:23:08 GMT server: Apache
set-cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9; expires=Tue, 08-May-2018 20:23:08 GMT; Max-Age=86400; path=/
status: 200 vary: Accept-Encoding via: e3s
Request Headers
:authority: www.example.com
:method: GET
:path: /forum/list.php?11
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9
cache-control: max-age=0
cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9;
referer: https://www.example.com/forum/addon.php?11,module=user_list
upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Windows NT 10.0;
Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/66.0.3359.139 Safari/537.36
And here is a follow-up Ajax call:
General
Request URL: https://www.example.com/forum/ajax.php?client
Request Method: GET Status Code: 200 (from memory cache)
Remote Address: x.x.x.x:443 Referrer Policy: no-referrer-when-downgrade
Response Headers
age: 734
cache-control: must-revalidate
content-encoding: gzip
content-length: 2862
content-type: text/javascript;charset=UTF-8
date: Mon, 07 May 2018 18:29:37 GMT
expires: Tue, 08 May 2018 02:29:37 GMT
pragma: cache
server: Apache
status: 200
vary: Accept-Encoding
via: e2s

#Sammitch was correct - phorum was not setting cache-control in the headers for most of my pages. This was causing my hosting service's own caching system to cache responses that included session cookies.
I fixed this by changing my .htaccess file as described here: https://stackoverflow.com/a/7664157/1411376
This seems to work for my server config, since the php code (phorum) had no code that set cache-control (except for ajax requests).

Related

Using Hydra to try a brute force attack on my login page wont work

I am just learning how to use Hydra for brute force attacks and am trying to test on a login page I have built for an old site. Some times I can get Hydra to run and attempt the attack but it never works even when I put in the correct password in my password.txt file. Any advice on why my code wouldnt be firing right would be great. I thought I had it right but I guess not.
Here are the things I think may be an issue but I cant seem to figure out whether they are or not.
the login form post to itself to verify the credentials
if the pw is wrong it out puts Oops, Wrong Username Or Password! (and I get issues if I use that entire string in my command)
maybe im not rooting to the proper location for my attack
also to note, the site is on sub directory of my site right now. Also the login uses just MD5 which I included both the password string and the MD5 version of the password in my password.txt file
Here is my command:
hydra 69.57.9.2 http-form-post "/john_smith_blog/admin_login/index.php:username=^USER^&password=^PASS^:Oops” -l JohnSmith -P password.txt -t 10 -w 30 -o hydra-http-post-attack.txt
Here is the Post data from wireshark
POST /john_smith/admin_login/index.php HTTP/1.1
Host: DomainNameDotCom
Connection: keep-alive
Content-Length: 359
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: DomainNameDotCom
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary3vaAYMlCejOUFLH5
Referer: DomainNameDotCom/john_smith/admin_login/index.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,nb;q=0.6
Cookie: __utmz=237398355.1442340459.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=237398355.593524857.1442328243.1442340459.1445019147.2; __unam=7639673-14fd22d2da8-49c4842-202; PHPSESSID=npth83ho7cg7di5bps0qtlm1i7; _ga=GA1.2.593524857.1442328243
------WebKitFormBoundary3vaAYMlCejOUFLH5
Content-Disposition: form-data; name="username"
JohnSmith
------WebKitFormBoundary3vaAYMlCejOUFLH5
Content-Disposition: form-data; name="password"
JohnSmith94
------WebKitFormBoundary3vaAYMlCejOUFLH5
Content-Disposition: form-data; name="Submit"
Login
------WebKitFormBoundary3vaAYMlCejOUFLH5--
HTTP/1.1 200 OK
Date: Sun, 22 Nov 2015 23:07:43 GMT
Server: Apache
X-Powered-By: PHP/5.3.6
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
49a
Oops, Wrong Username Or Password!
Any advice on why my code wouldnt be firing right would be great.
Are you using THC or did you make your own Hydra Version?
THC
Try to update your hydra and if not try to download the latest and double check your options.
Own Hydra Version
On what PL are you using? Try making your password.txt files in an array form and have your codes try to use array by array sequence. And in my opinion, First make a complete bruteforce.txt from 'a' to 'zzzzzzzzzzz' like that.
It's best to make your own that use others work. Just sayin :)
Make sure that the form parameters are the same as in the hydra attack (e.g. username and password).
Also keep in mind that the query which you have is designed to work on POST request form. You may need to put more parameters there (e.g. Login=Login or something like that).
To check that it would be best if you install a simple browser plugin (e.g. tamper data or headers) which when made in listening mode will be able to present you with the full post data request. From there you can just can modify your hydra parameters.
Good luck.

varnish not work only for one web site

I have a server with more site , after install varnish I tested if cache works, but for one web site not work varnish (have response of max-age=0). If I try to insert a simple php page (not correlated to main website) in same folder of this website, the response works.
This is a header when try :
HTTP/1.1 200 OK
Server: Apache/2.2.27 (Unix) mod_ssl/2.2.27 OpenSSL/1.0.1e-fips
X-Powered-By: PHP/5.2.17
Set-Cookie: PHPSESSID=ragejao4sm1kckjn1trvap3ft0; path=/
Vary: User-Agent,Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html
Cache-Control: max_age=8600
magicmarker: 1
Content-Length: 11863
Accept-Ranges: bytes
Date: Fri, 12 Jun 2015 12:28:15 GMT
X-Varnish: 1250916100
Age: 0
Via: 1.1 varnish
Connection: keep-alive
Varnish by default doesn't cache responses where cookies are set.
If you want to change this behaviour you need to consider how the cookie is being used (it looks like a session cookie) and either use the session id as part of the cache hash (ie so other users don't get a cached response from someone else's session) or use something like ESI to allow the "common" parts of the page to be cached while the session specific parts are fetched independently.
http://www.varnish-cache.org/trac/wiki/VCLExampleCacheCookies
https://www.varnish-cache.org/trac/wiki/ESIfeatures

html/php: Changing images order by swapping filenames doesn't take immediate effect

I have following problem that's bugging my mind completely. I have to take over this cms from someone who doesn't want to care for it anymore and is giving no support whatsoever.
Situation is as follows: on the site there are several photo albums which are populated by reading a directory in php. All is good there, pictures are shown in the order they are read. In the management system, these pictures can be changed in order by an up or down-button. The way this is done is by swapping the image's filenames. This works, when I change the order for an image i can see server-side the filenames have actually been swapped.
This is however not the case on the site, at least not immediately: it takes an average of 10 minutes to see the images swapped there. Ofcourse, my client can't work like this, and he claims it has always worked before. I have tried to turn off caching browser-side, this hasn't helped. I can also note the changes take effect on the same time in IE and FF. I tried several ways of turning off cache server-side in php too, also to no avail.
Is there any other place where I should be looking or could there be another reason why these changes don't take effect immediately?
In addition, changes i make to javascript don't get picked up immediately too. I installed fiddler and this is the request header for that js file:
GET http://www.nobel-country-gite.be/admin/modules/Photoalbum/js/album.js HTTP/1.1
Accept: application/javascript, /;q=0.8
Referer: http://www.nobel-country-gite.be/admin/index.php?page=pic&album=24
Accept-Language: nl-BE
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
If-Modified-Since: Wed, 27 May 2015 15:55:12 GMT
If-None-Match: "ba1248f5-138b-5171244a92f66"
DNT: 1
Host: www.nobel-country-gite.be
Pragma: no-cache
Cookie: __utmc=39679548; __utma=39679548.1608184058.1429963360.1432662247.1432664636.7; __utmz=39679548.1429963360.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=1; PHPSESSID=7uge1ltg2rc11q63untthrc5s1; __utma=1.459796341.1429963360.1432662247.1432664636.7; __utmz=1.1429963360.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Response header is as follows:
HTTP/1.1 304 Not Modified
Server: Apache
Last-Modified: Wed, 27 May 2015 15:55:12 GMT
ETag: "ba1248f5-138b-5171244a92f66"
Vary: Accept-Encoding
Content-Type: application/javascript
Date: Wed, 27 May 2015 16:57:55 GMT
X-Varnish: 1826689067 1825041752
Age: 556
Via: 1.1 varnish
Connection: keep-alive
I would expect the answer to be different instead of 'not modified'?
Edit - upon waiting a few minutes and refreshing the page again, the response for this file is what is expected:
HTTP/1.1 200 OK
Server: Apache
Last-Modified: Wed, 27 May 2015 16:57:30 GMT
ETag: "ba1248f5-1387-51713237ac28e"
Vary: Accept-Encoding
Content-Type: application/javascript
Transfer-Encoding: chunked
Date: Wed, 27 May 2015 17:03:43 GMT
X-Varnish: 1827728442
Age: 0
Via: 1.1 varnish
Connection: keep-alive
I couldn't help but notice you are using Varnish (indicated by the X-Varnish response header). Varnish is a caching reverse proxy, which means your pages are not just being cached by the browser, but also on the server (by Varnish). Your browser connects to Varnish, and Varnish connects to your Apache backend.
The first response header includes "Age: 556" - that's the cached version's age in seconds (almost 10 minutes). Then the age comes across as "0" when the page refreshes - that's because Varnish has updated its cache. Probably you can access the page over HTTPS to see your changes immediately reflected (Varnish doesn't work for HTTPS and most people don't bother setting up an HTTPS cache), or you can generally add garbage GET parameters to your URL (e.g. "?bogus=123") to force Varnish to re-fetch the page (this won't make other users see the new version, since they'll be accessing via the normal URLs).
Fixes: You can use varnishadm to ban (expire) certain URLs in Varnish when you've made a change; you can modify the "Cache-Control" or "Expires" headers your CMS/Apache (via PHP, .htaccess, etc.) produces to reduce cache time (Varnish completely respects cache control headers in its caching strategy); you can change Varnish's behavior by editing the relevant VCL (usually "default.vcl"); or you can accept that caches are generally good (they save a lot of time and resources in generating the response), and maybe a 10 minute delay is an acceptable trade-off.

Display HTTP Response on Webpage using PHP

I am looking to put together a website that displays the full HTTP Request Headers and HTTP Response Headers for the loading of the page itself. For instance. If someone browses to http://example.com/index.php , I want the following to display:
HTTP Request
GET /index.php HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
HTTP Response
HTTP/1.1 200 OK
Date: Mon, 21 Dec 2011 10:20:46 GMT
Server: Apache/2.2.15 (Red Hat)
X-Powered-By: PHP/5.3.3
Content-Length: 1169
Connection: close
Content-Type: text/html; charset=UTF-8
We were able to get the Request header to display fairly simply using the following PHP code:
print $_SERVER['REQUEST_METHOD']." ".$_SERVER['REQUEST_URI']." ".$_SERVER['SERVER_PROTOCOL']."<br>";
foreach (apache_request_headers() as $name => $value)
echo "$name: $value<br>";
But are having some difficulties with the HTTP Response header. Anyone have any ideas of how we can do this? It does not have to be PHP if you have a method that works in Perle or CGI or whatever.
To be clear, I don't mean to set the HTTP Response to anything specific, only display the response served by the web server to load the page.
You want to use headers_list()
http://www.php.net/manual/en/function.headers-list.php
headers_list() will return a list of headers to be sent to the browser / client. To determine whether or not these headers have been sent yet, use headers_sent().
Well here is the issue, the response header is generated after the PHP (or any server-side language for that matter) has already completed its job.
To put it in english its like the post man handing you a letter and you asking him to explain how the process of handing you the letter went. He will probably just look at you dumb.
You will need a client-side language (ie. JavaScript) to perform this task.
Use PHP to get the headers sent to the web Server.
http://www.php.net/manual/en/function.apache-request-headers.php
Use JavaScript to get headers sent by the web server. I would suggest using jQuery for that.
http://api.jquery.com/jQuery.ajax/#jqXHR
This way you are sure that you get all the headers which are either received by the web server or the browser.
Check out get_headers in PHP Manual

PHP isn't saving session when it's an ajax call

Hi all,
i'm testing out a service for internal ads on our website...
I need to save internal session (PHP) to know what ads have been displayed and some other protection stuff...
The problem is that if i access to the API throught webbrowser GET or POST it does session (and saves the cookie of php session), but if i use jQuery.ajax() method it doesn't save it...
My link for tests is http://search.microdual.com
(this is because i wanted a customized google search on my laptop :p)
I suggest you to use firebug to take a look at the javascript code. (PHP code isn't needed because it is working on clicks...)
To simplify the debugging, i print out on response json array from server the session id on the var {id_sessao:"..."}...
Thanks in advance,
José Moreira
EDIT:
Headers from server:
Date Wed, 08 Sep 2010 11:24:48 GMT
Server Apache/2.2.8 (Ubuntu)
P3P CP="NOI NID ADMa OUR IND UNI COM NAV"
Cache-Control private, must-revalidate
Access-Control-Allow-Orig... *
Access-Control-Allow-Cred... true
Access-Control-Allow-Meth... OPTIONS, GET, POST
Access-Control-Allow-Head... Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control
Set-Cookie SN4b55935921bde=7ad280272050b4b44f17769909fd6f34; path=/ SN4b55935921bde=7ad280272050b4b44f17769909fd6f34; path=/
Keep-Alive timeout=15, max=97
Connection Keep-Alive
Transfer-Encoding chunked
Content-Type text/html; charset=UTF-8
Headers from the jQuery Ajax request:
Host www.microdual.com
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; pt-PT; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
Accept application/json, text/javascript
Accept-Language pt-pt,pt;q=0.8,en;q=0.5,en-us;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Referer http://search.microdual.com/
Content-Length 29
Origin http://search.microdual.com
Pragma no-cache
Cache-Control no-cache
Where is the cookie control on the jQuery Ajax Request?
The problem is probably that your parent document is on search.microdual.com, and you are requesting a script from www.microdual.com. The session cookie isn't transported across domains.
If you are not using document.domain - I don't see it anywhere? - you will also have the additional problem that the AJAX call fails due to the Single Origin Policy.
To fix the cookie issue, you could either
set the cookie's domain to .microdual.com so it works in both sub-domains
carry the session across manually in the URL (?sessionid=xxxxx) and continue the session using session_id("xxxxx");.
put both scripts on the same sub-domain (search.microdual.com)
The latter would be the easiest way.

Categories