Jump to content

cPanel and WHMCS - Suspending accounts from SSH


Recommended Posts

Dealing with spam / malware is never easy. When dealing with a cPanel/WHMCS combination, welll, it's a bit more complicated. It often goes a bit like this.

 

Login via SSH

Find out which user is causing spam

Suspend account

Clean out spam

Login to WHM

Find out what user owns said spamming account

Login to WHMCS

Find out what billing user is associated with said user

Send out lengthy notification of abuse and suspension

It would really be nice if this could all be done in a condensed version, right? RIGHT? Well, here you go (you're welcome). This will require a few steps initially, but in the end, it will pay off with one simple command to suspend/notify the user.

 

Step 1:

Place the following code in a file. This is an sh file

 

#!/usr/bin/env bash
#Command line tool to suspend account and notify user via ticket
shopt -s extglob

args=("$@")
user=${args[0]}
date=`date +%F-%k%M`
function show_usage
{
echo -e "Syntax:
suspendacct.sh user";
exit 1
}
if [ -z "$user" ]
then
show_usage
fi
echo -e "Working with:\t $user";
/scripts/suspendacct $user 'spamming' 1
reseller=$(whmapi1 accountsummary user=$user | grep owner)
output="${reseller##*( )}"
realseller=${output:7}
echo -e "Reseller is:\t $realseller";
suspdomain=$(whmapi1 accountsummary user=$user | grep "domain:")
output3="${suspdomain##*( )}"
realdomain=${output3:8}
echo -e "Domain is:\t $realdomain";
owneremail=$(whmapi1 accountsummary user=$realseller | grep "email:")
output2="${owneremail##*( )}"
realemail=${output2:7}
echo -e "Owner Email is:\t $realemail";
ownerdomain=$(whmapi1 accountsummary user=$reseller | grep "domain:")
output4="${ownerdomain##*( )}"
ownerdomain=${output4:8}
echo -e "Owner Domain:\t$ownerdomain";
echo -e "Creating Ticket for $realdomain [$realemail]";
php /path/to/filename $realdomain $realemail $realseller $ownerdomain

 

The only thing you need to modify is the /path/to/filename . That is where you're going to place

 

Step 2:

Place the following code in a php file on your server somewhere.

 

<?php
require_once("whmcs_abuse.inc");
$domain = $argv['1'];
$email = $argv['2'];
$email = str_replace(' ', '', $email);
$reseller = $argv['3'];
$odomain = $argv['4'];
print"Domain:\t $domain\n";
print"Email:\t $email\n";
$ticketsubject .= " $domain";
print "$ticketsubject" ;

$postfields = array(
   'username' => $username,
   'password' => md5($password),
   'action' => 'getclientsproducts',
   'username2' => $reseller,
   'domain' => $odomain,

   'responsetype' => 'json',
);


// Call the API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . 'includes/api.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
$response = curl_exec($ch);
if (curl_error($ch)) {
   die('Unable to connect: ' . curl_errno($ch) . ' - ' . curl_error($ch));
}
curl_close($ch);
$jsonData = json_decode($response, true);
$array1 = $jsonData['products'];
$array2 = $array1['product'];
$array3 = $array2['0'];
//print_r($array3);
$clientid= $array3['clientid'];
print ("\nClient id: $clientid\n");


if (empty($clientid))
{
die("I cannot open a ticket. Please manually lookup reseller $reseller\n");
}

// Set post values
$postfields = array(
   'username' => $username,
   'password' => md5($password),
   'action' => 'OpenTicket',
   'clientid' => $clientid,
   'markdown' => 1,
   'email' => $email,
   'deptid' => $deptid,
   'subject' => $ticketsubject,
   'message' => $ticketbody,
   'priority' => 'high',


   'responsetype' => 'json',
);


// Call the API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . 'includes/api.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
$response = curl_exec($ch);
if (curl_error($ch)) {
   die('Unable to connect: ' . curl_errno($ch) . ' - ' . curl_error($ch));
}
curl_close($ch);
// print_r($response);

// Attempt to decode response as json
$jsonData = json_decode($response, true);
$ticketid = $jsonData['id'];
print "Ticket id:\t $ticketid";

/*
Update the ticket to the necesary status. Must be done after ticket submission
Anything below here is optional
*/

$postfields = array(
   'username' => $username,
   'password' => md5($password),
   'action' => 'updateticket',
   'ticketid' => $ticketid,
   'status' => $ticketstatus,
   'responsetype' => 'json',
);


// Call the API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . 'includes/api.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
$response = curl_exec($ch);
if (curl_error($ch)) {
   die('Unable to connect: ' . curl_errno($ch) . ' - ' . curl_error($ch));
}
curl_close($ch);
$jsonData = json_decode($response, true);
?>

 

Now, edit the first file. Point to this file in the last line.

 

Step 3:

One last file here. Call this whmcs_abuse.inc. Place it in the same directory as the file from step 2

 

<?php
$url = "; # WHMCS url
$username = ""; # Admin username goes here
$password = ""; # Admin password goes here
$ticketsubject = "Abuse notification for";
$deptid = ""; #what department do you want this in
$ticketstatus = "Customer To Reply"; #what status do you want to place this in
$ticketbody = "Hello,

It's come to our attention that your domain  has been the target of some very abusive activity, causing your server to have an excessive email queue

Due to the excessive amount of spam coming from this domain, we've had to suspend this account.
Please note that you may unsuspend this, but we do require that until you resolve the issue, you make this site available to you and your employees only.
To do this, you may add the following to your .htaccess file.

```
<Limit GET POST>
order deny,allow
deny from all
ALLOW FROM your ip
</Limit>
```

Please note that you **must** run a full scan and update any vulnerable software, themes, plugins, or code in order to ensure that this does not continue.

This activity is most often caused by out of date, or vulnerable plugins , software, or templates. Please do ensure that your software, templates and plugins are all at the latest version and not vulnerable to any sort of hacking activity in order to ensure that this does not happen again.";

 

 

Step 4:

Add your server's IP to the API IP Access Restriction list (admin -> setup -> security, toward the bottom of the page). Make sure to save your settings

 

Now, you have a working script. Assuming you've edited the first script, you've saved yourself a ton of time, and you can simply do the following to investigate and suspend spammers, assuming you named the script suspendacct.sh

 

suspendacct.sh username

 

This will suspend the account, send the informational email to the client, and save you a few steps in the process.

 

Note:

This line from the first script will remove the ability for the reseller to unsuspend this account:

/scripts/suspendacct $user 'spamming' 1

This is somewhat necessary I've found, as resellers tend to unsuspend and then not address the problem.

This will force them to reply to the ticket, acknowledge the problem and let you know what they plan on doing to fix the issue.

You can change this to

/scripts/suspendacct $user 'spamming' 0

to avoid this behavior.

Edited by twhiting9275
Link to comment
Share on other sites

  • 5 months later...

Merry Christmas, I've taken a bit of time and updated this so that it will actually work properly . While it worked before, there were a few issues with it

 

Bug Fixes

-- WHMCS wouldn't notify if a direct customer (not reseller) was suspended -- Fixed

-- Correct domain in subject. Previously , the script went off of the account's main domain. Now a second argument is required and passed to the php script. This will reflect in the ticket subject

 

New Features

-- Added logs for staff viewing . 3 notes will be added after ticket creation

-- exigrep /home/user

-- exigrep $abusedomain

-- exim -bp | grep $abusedomain

This should help resolve, or identify issues

 

-- Added ID / server /domain to ticket as a staff note for quick reference

-- New ticket no longer created if client has an open ticket for this same domain , ticket is replied to instead.

-- Universal CurlPost, cleaning up the code a good bit.

 

Files are included in the zip file attached.

You'll have to change the file called (last line of the bash script), and edit whmcs_abuse.inc for your own personal taste, but this should be all that's needed.

 

As always, if problems, let me know and I'll see if I can fix them for you :)

Suspend.zip

Link to comment
Share on other sites

  • 11 months later...

Hi thank you so much for this useful scrop by the way how about if the account was from the master reseller how can i edit the scrip to locate the mater reseller i am getting this error 

 

[root@sv2 ~]# sh suspendacct.sh sinergiahumana sinergiahumana.net 

Working with: sinergiahumana

Changing Shell to /bin/false...Done

Locking Password...Done

Suspending email account logins for sinergiahumana.net .... Done

Suspending mysql users

Account previously suspended (password was locked).

Suspending websites...

Suspending outgoing email....Done

sinergiahumana's account has been suspended

Reseller is: hostserv

Domain is: <removed Personal INformation>

Owner Email is: <removed Personal INformation>

Owner Domain:

Creating Ticket for<removed Personal INformation>

Content-type: text/html; charset=UTF-8

 

I'm sorry, I'm unable to open a ticket for hostserv. Please double check the username or WHMCS database for sinergiahumana.net

Edited by WHMCS ChrisD
Removed PII
Link to comment
Share on other sites

  • 1 year later...
  • 1 year later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated