Go Back   vb.org Archive > vBulletin 4 Discussion > vB4 Programming Discussions
FAQ Community Calendar Today's Posts Search

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #1  
Old 07-30-2016, 10:39 AM
kerrghann's Avatar
kerrghann kerrghann is offline
 
Join Date: Jul 2012
Location: Hawaii
Posts: 45
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default Better AdminCP/ModCP Security Scripts

So, to start, I'm not exactly sure where to put this. It's something I've worked out for me and my assistant. I'm obsessed with security, to a degree, and I utilize .htaccess and .htpasswd to a high degree on my site.

Generally speaking, I use it to lock down the admincp and modcp (things that an attacker, who managed to high-jack an account, could do serious damage with).

So, this set of PHP files is essentially a dual/redundant password system. I've requested from my staff that they use a password that is DIFFERENT from their forum password to access the admin and moderator control panels.

So basically here we create a custom vbulletin page. I used Lynne's guide that I found here

transcendence.php (forum root)
PHP Code:
<?php
// ####################### SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);

// #################### DEFINE IMPORTANT CONSTANTS #######################

define('THIS_SCRIPT''transcendence');
define('CSRF_PROTECTION'true);
// change this depending on your filename

// ################### PRE-CACHE TEMPLATES AND DATA ######################
// get special phrase groups
$phrasegroups = array();

// get special data templates from the datastore
$specialtemplates = array();

// pre-cache templates used by all actions
$globaltemplates = array('transcendence',
);

// pre-cache templates used by specific actions
$actiontemplates = array();

// ######################### REQUIRE BACK-END ############################
// if your page is outside of your normal vb forums directory, you should change directories by uncommenting the next line
// chdir ('/path/to/your/forums');
require_once('./global.php');

// #######################################################################
// ######################## START MAIN SCRIPT ############################
// #######################################################################

$navbits construct_navbits(array('' => 'Expect Transcendence'));
$navbar render_navbar_template($navbits);

// ###### YOUR CUSTOM CODE GOES HERE #####
$pagetitle 'Expect Perfection - Expect Transcendence';

// ###### NOW YOUR TEMPLATE IS BEING RENDERED ######

$templater vB_Template::create('transcendence');
$templater->register_page_templates();
$templater->register('navbar'$navbar);
$templater->register('pagetitle'$pagetitle);
print_output($templater->render());

?>
You'll then want to create your own template for it. I'm including mine as I've done quite a bit of work with it (to include the form that you submit with and allowing only certain usergroups to access it). Dave answered a question I had in regards to vbulletin syntax and linked me to this great list that I also feel like sharing!

The easiest way to edit all your templates is to go into debug mode (I have a password set for mine in my vbulletin config file). This allows you to edit the master style and add it to all of your styles at the same time. I'm sure there is an easier way as well and I also must warn you to not mess around with it too much. I accidentally deleted my postbit_legacy and have yet to find a way to get it back...haha... Good thing I don't use legacy...

Anyways, now the template!

transcendence (template)
PHP Code:
{vb:stylevar htmldoctype}
<
html xmlns="http://www.w3.org/1999/xhtml" dir="{vb:stylevar textdirection}" lang="{vb:stylevar languagecode}" id="vbulletin_html">
  <
head>
    <
title>{vb:raw vboptions.bbtitle} - {vb:raw pagetitle}</title>
    {
vb:raw headinclude}
    {
vb:raw headinclude_bottom}
  </
head>
  <
body>
    
    {
vb:raw header}
    
    {
vb:raw navbar}
    
    <
div id="pagetitle">
      <
h1>{vb:raw pagetitle}</h1>
    </
div>
    
    <
h2 class="blockhead">Title</h2>
    <
div class="blockbody">
      <
div class="blockrow">
            <
vb:if condition="is_member_of($bbuserinfo, 6,7,26,27)">
                  <
center>
                        <
h1><B><U>Administrative Panel Access Form</u></b></h2>
                        <
h4><I>Input your username.  Then a password that IS NOT your current forum password (alpha numeric onlyno special charactersat least 8 characters long)</i></h4><br/>

<
i>Do note that your USERNAME and PASSWORD are case sensitive.  I haven't set up validation on this form.  Please don't screw around with it as it could damage the site.  Thank you.<br/>

<
hr/>
                        <
form name="transcend" action="hash.php" method="post">
                              <
table cellspacing="30">
                                    <
tr>
                                          <
th>Username</th>
                                          <
th>Password</th>
                                          <
th>Email</th>
                                    </
tr>
                                    <
tr>
                                          <
td><input type="text" name="username"/></td>
                                          <
td><input type="password" name="password"/></td>
                                          <
td><input type="text" name="email"/></td>
                                    </
tr>
                                    <
tr>
                                          <
td><input type="submit"/></td>
                                          <
td></td>
                                          <
td></td>
                                    </
tr>
                              </
table>
                        </
form>
<
hr/><br/><br/>
                  </
center>
            </
vb:if>
      </
div>
    </
div>
    
    {
vb:raw footer}
  </
body>
</
html
I made it so only my staff could actually see and use the form on this page by adding in this piece of code:

PHP Code:
<vb:if condition="is_member_of($bbuserinfo, 6,7,26,27)">
FORM HERE
</vb:if> 
Just an added precaution.

The form has an action="hash.php"

This is the script I made to hash the password submitted by this form to the APR1 md5 format. It then appends this hashed password automagically to your .htpasswd file (which should be outside of your public_html folder, I do mine one up from it (../.htpasswd))

This sounds dangerous right? If someone managed to get an admin/mod account...they could find this page and then simply give themselves a new admincp login, correct? That's why this form ALSO adds a # in front of the line, making it a comment meaning it can't be used until a server administrator opens up the .htpasswd file and removes the comment at the beginning!

This sounds like a bit of work, however, I promise you it's a lot less work then requesting that a staff member hash their password, give you the hashed password, you go into your .htaccess file and add it, and do this for all your staff members. It's easier to give them a link to the transcendence.php page and uncomment it once they finish.

The hash.php file goes a step further and also sends you an email whenever someone submits the form. It includes their username, their password, their email, and their IP address.

Now here is the hash.php script, it should be in your forum root with transcendence.php

hash.php (forum root)
PHP Code:
<?php
$ini 
parse_ini_file("includes/config.ini.php");
// Create connection
function crypt_apr1_md5($plainpasswd)
{
    
$salt substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 08);
    
$len strlen($plainpasswd);
    
$text $plainpasswd.'$apr1$'.$salt;
    
$bin pack("H32"md5($plainpasswd.$salt.$plainpasswd));
    for(
$i $len$i 0$i -= 16) { $text .= substr($bin0min(16$i)); }
    for(
$i $len$i 0$i >>= 1) { $text .= ($i 1) ? chr(0) : $plainpasswd{0}; }
    
$bin pack("H32"md5($text));
    for(
$i 0$i 1000$i++)
    {
        
$new = ($i 1) ? $plainpasswd $bin;
        if (
$i 3$new .= $salt;
        if (
$i 7$new .= $plainpasswd;
        
$new .= ($i 1) ? $bin $plainpasswd;
        
$bin pack("H32"md5($new));
    }
    for (
$i 0$i 5$i++)
    {
        
$k $i 6;
        
$j $i 12;
        if (
$j == 16$j 5;
        
$tmp $bin[$i].$bin[$k].$bin[$j].$tmp;
    }
    
$tmp chr(0).chr(0).$bin[11].$tmp;
    
$tmp strtr(strrev(substr(base64_encode($tmp), 2)),
    
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
    
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
 
    return 
"$"."apr1"."$".$salt."$".$tmp;
}
 
$username $_POST["username"]; /* Get USERNAME from FORM @ transcendence.php */
$password $_POST["password"]; /* Get PASSWORD from FORM @ transcendence.php */

try {
    
$db = new PDO('mysql:host=localhost;dbName=' $ini['databaseName'], $ini['databaseUsername'], $ini['databasePassword'], array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ));

    
$check $db->prepare("SELECT * FROM " $ini['databaseName'] . ".user WHERE username = ?");
    
$check->execute(array($username));
    
$result $check->fetchAll();
    
    foreach(
$result as $row) {
    
$vbPassword $row['password'];
    
$vbSalt $row['salt'];
    
$yourSubmittedPassword md5(md5($password) . $vbSalt);
    if (
$vbPassword == $yourSubmittedPassword) {
        echo(
"<center><h1>I'm sorry, your password cannot be the same as your vBulletin Password.  Try again!</h1></center>");
        
$db null;
        die();
    } else {

    
$hashedPassword crypt_apr1_md5($password); /* Password is hashed using APR1 format */
 
    
$theHash "# " $username ':' $hashedPassword/* Comments out the .htpasswd entry for approval */
    
file_put_contents($ini['htpasswdLocation'], $theHash.PHP_EOLFILE_APPEND); /* Hashed PASSWORD is appended to the end of .htpasswd file */

    
$to $ini['adminEmail'];
    
$subject $ini['emailSubject'];
    
$headers = array();
    
$headers[] = "MIME-Version: 1.0";
    
$headers[] = "Content-type: text/plain; charset=iso-8859-1";
    
$headers[] = "From: Transcendence <" $ini['adminEmail'] . ">";
    
$headers[] = "Reply-To: " $_POST["username"] . " <" $_POST["email"] . ">";
    
$headers[] = "Subject: {$subject}";
    
$headers[] = "X-Mailer: PHP/" phpversion();

    
$message "Greetings <B>" $ini['administrator'] . "</B>,\r\n\r\nA user has requested access to the Administrative Control panel via the Transcendence page.\r\n\r\nThe Users Info is as Follows:\r\n\r\n<B>Username</B>: <I>" $_POST["username"] . "</I>\r\n" "<B>Email</b>: <I>" $_POST["email"] . "</I>\r\n" "<B>IP Address</B>: <I>" $_SERVER['REMOTE_ADDR'] . "</I>\r\n" "<B>Hashed Password</B>: <I>" $theHash "</I>\r\n\r\nConfirm with the User that they have requested this access.  If they have, please go to the .htpasswd file and uncomment their hashed password to give them access.  Thank you!\r\n\r\n\r\nTranscendence\r\n" $ini['siteName'] . " at It's Finest";

    
$message wordwrap($message70"\r\n");

    
mail($to$subject$messageimplode("\r\n"$headers));

     echo(
"<center><h1>Thank You " $username "</h1><br/><br/>Your request has been submitted and an email has been sent to " $ini['administrator'] . ".</center>");
    }
}
    
$db null;
} catch (
PDOException $e) {
    echo(
"Error: " $e->getMessage() . "<br/>");
    die();
}
?>
Rather then set all the variables in the hash.php file, I've made it so that it parses and config.ini.php file. You can edit most of the variables through it.

Here is the config.ini.php file, it should be in your includes folder. Make sure you call it config.ini.php, the php at the end is important as .ini files can be opened and read as plaintext.

config.ini.php (./forumRoot/includes)
PHP Code:
;<?php
;die(); /* DO NOT REMOVE THIS */
;/*
[DATABASE]
serverName = localhost
databaseUsername = yourDatabaseUsername
databasePassword = yourDatabasePassword
databaseName = YourDatabaseName

[BASIC INFORMATION]
administrator         = yourNameHere
siteName            = yourSiteNameHere

[HTPASSWD LOCATION]
htpasswdLocation    = ../.htpasswd

[EMAIL INFORMATION]
emailSubject         = Administrative Request
serverEmail            = whoYouWantTheEmailToComeFrom
adminEmail            = yourEmailHere
bccEmail            = secondaryEmailAddressToBCC
bccName             = nameOfPersonBeingBCC
;?>
Now any directory you want to password protect with .htaccess will require this in the directory:

.htaccess (per directory you want to protect)
Code:
AuthType Basic
AuthName "You Shall Not Pass"
AuthUserFile /path/to/.htpasswd
Require valid-user
You'll also want to decide where you wish to store your .htpasswd file, as stated, I keep mine 1 directory up from my forum. However, my forum is located at www.mywebsitehere.com, if your forum is located at something along the lines of www.mywebsitehere.com/forum/ you'll want to place your .htpasswd file at least 2 directories up (../../.htpasswd). It's important to keep it outside of your public_html/www folders.

That's pretty much it.


Things I'd like to do in the future


Form Verification
I'd like to add form validation in the template, however my javascript seems like it doesn't want to execute. I had this in the head section of my transcendence template:

HTML Code:
  <script>
function validateForm() {
    var x = document.forms["transcend"]["username"].value;
    var y = document.forms["transcend"]["password"].value;
    var z = document.forms["transcend"]["email"].value;
    if (x == null || x == "" || y == null || y == "" || z == null || z == "") {
        alert("All fields must be filled in");
        return false;
    }
}
  </script>
[s]Check against current vBulletin password Hash
I'd like to write a script that compares the password they requested to their current vbulletin hash. This would, essentially, require me to hash the password they submit twice. First it would hash it in the format of that vBulletin 4 uses, then compare it to the one in the database. If it matches, it throws an error and refuses to let them use that password. If it doesn't match, it continues and rehashes their submitted password in the APR1 format. If anyone would like to help me with this, I'd really appreciate it![/s] Completed!

Well, I do hope this helped someone and I also really hope I put this in the correct place. I felt like contributing something that I found useful and helpful for managing my forum. Please let me know if I committed any sins against grammar/punctuation or if anything in my code is seriously flawed or dangerous.

Much appreciated!
Reply With Quote
2 благодарности(ей) от:
Dragonsys, IggyP
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 05:01 AM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.04257 seconds
  • Memory Usage 2,698KB
  • Queries Executed 12 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (1)bbcode_code
  • (1)bbcode_html
  • (6)bbcode_php
  • (2)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)navbar
  • (3)navbar_link
  • (120)option
  • (5)post_thanks_box
  • (2)post_thanks_box_bit
  • (5)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (1)post_thanks_postbit
  • (5)post_thanks_postbit_info
  • (5)postbit
  • (5)postbit_onlinestatus
  • (5)postbit_wrapper
  • (1)showthread_list
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_threadedmode.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_postinfo_query
  • fetch_postinfo
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids_threaded
  • showthread_threaded_construct_link
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • fetch_musername
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • post_thanks_function_fetch_thanks_bit_start
  • post_thanks_function_show_thanks_date_start
  • post_thanks_function_show_thanks_date_end
  • post_thanks_function_fetch_thanks_bit_end
  • post_thanks_function_fetch_post_thanks_template_start
  • post_thanks_function_fetch_post_thanks_template_end
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete