NEW - Dynamic theme selection

This commit is contained in:
Ludovic COULON
2021-11-21 16:50:14 +01:00
parent d2a2376267
commit 8aa7e9ba07
28 changed files with 2774 additions and 2587 deletions

View File

@@ -13,60 +13,61 @@
"author": "Ludovic COULON & Riadh BOUCHAHOUA",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.14.8",
"@babel/core": "^7.15.0",
"@babel/cli": "^7.16.0",
"@babel/core": "^7.16.0",
"@babel/helper-call-delegate": "^7.12.13",
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.16.0",
"@babel/preset-env": "^7.16.4",
"@babel/preset-react": "^7.16.0",
"@babel/preset-typescript": "^7.15.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.2",
"@types/antd": "^1.0.0",
"@types/crypto-js": "^4.0.2",
"@types/pretty": "^2.0.0",
"@types/react-query": "^1.2.9",
"@types/react-syntax-highlighter": "^13.5.2",
"@types/use-persisted-state": "^0.3.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.2.0",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^10.0.0",
"css-loader": "^6.5.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.3.2",
"html-webpack-plugin": "^5.5.0",
"react-hot-loader": "^4.13.0",
"style-loader": "^3.2.1",
"typescript": "^4.3.5",
"webpack": "^5.50.0",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.0.0"
"react-refresh": "^0.11.0",
"style-loader": "^3.3.1",
"typescript": "^4.4.3",
"webpack": "^5.64.1",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.5.0"
},
"browserslist": [
">0.2%",
"not dead",
"not op_mini all"
],
"browserslist": [ ">0.2%", "not dead", "not op_mini all" ],
"dependencies": {
"@ant-design/icons": "4.6.2",
"@ant-design/icons": "4.7.0",
"@hot-loader/react-dom": "^17.0.1",
"@types/chrome": "^0.0.154",
"@types/jest": "^27.0.1",
"@types/node": "^16.6.1",
"@types/react": "^17.0.18",
"@types/chrome": "^0.0.164",
"@types/jest": "^27.0.3",
"@types/node": "^16.11.9",
"@types/react": "^17.0.27",
"@types/react-dom": "^17.0.9",
"antd": "4.16.12",
"antd": "4.16.13",
"antd-mask-input": "0.1.15",
"axios": "^0.21.1",
"axios": "^0.24.0",
"crypto-js": "^4.0.0",
"escape-quotes": "^1.0.2",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"pretty": "^2.0.0",
"rc-queue-anim": "^2.0.0",
"react": "^17.0.2",
"react-chrome-extension-router": "^1.2.0",
"react": "latest",
"react-chrome-extension-router": "^1.3.1",
"react-clipboard.js": "2.0.16",
"react-dom": "^17.0.2",
"react-query": "^3.19.6",
"react-syntax-highlighter": "^15.4.3",
"react-dom": "latest",
"react-query": "^3.33.1",
"react-refresh-typescript": "^2.0.2",
"react-syntax-highlighter": "^15.4.5",
"sm3": "^1.0.3",
"ts-loader": "^9.2.5",
"ts-loader": "^9.2.6",
"use-persisted-state": "^0.3.3"
}
}

View File

@@ -1,5 +1,3 @@
@import '~antd/dist/antd.dark.min.css';
.logo {
height: 32px;
margin: 16px;
@@ -26,8 +24,11 @@
}
}
.ant-badge {
color: inherit !important;
}
.site-layout .site-layout-background {
background: #0f0f0f !important;
border-radius: 10px;
}
.ant-menu-inline .ant-menu-item:not(:last-child),
@@ -206,5 +207,4 @@ h5.ant-typography,
body {
min-width: 750px;
min-height: auto;
background-color: black;
}

View File

@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { Layout, Menu, Typography, Button, Badge } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { Layout, Menu, Typography, Button, Badge, Select, } from 'antd';
import { CopyrightCircleOutlined, FullscreenOutlined, ArrowsAltOutlined } from '@ant-design/icons';
import { createFromIconfontCN } from '@ant-design/icons';
import { goTo } from 'react-chrome-extension-router';
@@ -7,7 +7,6 @@ import ReverseShell from './linux/ReverseShell';
import PhpReverseShell from './web/PhpReverseShell';
import TtySpawnShell from './linux/TtySpawnShell';
import Base64Encode from './encoding/Base64Encode';
import HexEncode from './encoding/HexEncode';
import Hashing from './encoding/Hashing';
import LinuxCommands from './linux/LinuxCommands';
import PowershellCommands from './linux/PowershellCommands';
@@ -20,6 +19,8 @@ import FileTransfer from './file_transfer/File_transfer';
import PersistedState from 'use-persisted-state';
import MSFBuilder from './linux/MSFBuilder';
import HTTPUtils from './http_utils/HTTP-Utils';
import DynamicTheme from '../theming';
import { themes } from '../themes';
const { Paragraph } = Typography;
const { Sider, Content, Footer } = Layout;
@@ -27,9 +28,23 @@ const IconFont = createFromIconfontCN({
scriptUrl: [ './iconfont.js' ]
} );
const defaultTheme = themes[ 0 ];
const options = themes.map( ( theme ) => ( {
label: theme.displayName,
value: theme.id
} ) );
export default function LayoutApp ( props: {
children: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined;
} ) {
const useDefaultTheme = PersistedState( 'default_colored_theme' );
const [ themeId, setThemeId ] = useDefaultTheme( defaultTheme.id );
const selectThemeId = useCallback(
( option ) => setThemeId( option as string ),
[]
);
interface IRouterComponent {
key: string;
icon: JSX.Element;
@@ -64,7 +79,11 @@ export default function LayoutApp(props: {
},
{
key: '5',
icon: <IconFont type='icon-powershell' style={{ fontSize: '1.5em', marginTop: 3 }} />,
icon: (
<Badge dot size='default' style={{ transform: `translate(3px, 5px)` }}>
<IconFont type='icon-powershell' style={{ fontSize: '1.5em', marginTop: 3 }} />
</Badge>
),
name: 'PowerShell Commands',
componentRoute: PowershellCommands
},
@@ -110,7 +129,7 @@ export default function LayoutApp(props: {
name: 'Feed RSS',
componentRoute: FeedRSS
},
{
/* {
key: '13',
icon: (
<Badge dot size='default' style={{ transform: `translate(3px, 5px)` }}>
@@ -119,9 +138,9 @@ export default function LayoutApp(props: {
),
name: 'HTTP Repeater',
componentRoute: HTTPUtils
},
}, */
{
key: '14',
key: '13',
icon: (
<Badge dot size='default' style={{ transform: `translate(3px, 5px)` }}>
<IconFont type='icon-shield' style={{ fontSize: '1.5em', marginTop: 3 }} />
@@ -131,7 +150,7 @@ export default function LayoutApp(props: {
componentRoute: MSFBuilder
},
{
key: '15',
key: '14',
icon: <IconFont type='icon-about' style={{ fontSize: '1.5em', marginTop: 3 }} />,
name: 'About us',
componentRoute: AboutUs
@@ -215,6 +234,13 @@ export default function LayoutApp(props: {
Fullscreen mode
</a>
</Button>
<DynamicTheme themes={themes} value={themeId} />
<Select
value={themeId}
style={{ minWidth: 200 }}
options={options}
onSelect={selectThemeId}
/>
<Button icon={<ArrowsAltOutlined style={{ margin: 5 }} />} onClick={() => windowMode()} type='link'>
Pop-up mode
</Button>

View File

@@ -56,13 +56,17 @@ export default function PowershellCommands() {
const ACL_gpoedit_rights = `Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name}`;
const ACL_passwd_edit_rights = `Get-ObjectAcl -SamAccountName labuser -ResolveGUIDs -RightsFilter "ResetPassword"`;
// dump user accounts
const local_recon_ldifde = `ldifde -d "OU=THING,DC=CHANGE,DC=ME" -p subtree -f dump.ldf`
const local_recon_csvde = `csvde -d "OU=THING,DC=CHANGE,DC=ME" -p subtree -f dump.csv`
return (
<QueueAnim delay={300} duration={1500}>
<Title level={2} style={{ fontWeight: 'bold', margin: 15 }}>
Powershell handy commands
</Title>
<Paragraph style={{ margin: 15 }}>List of useful Powershell commands</Paragraph>
<Divider dashed />
<Divider orientation='center'></Divider>
<div
key='a'
style={{
@@ -92,8 +96,7 @@ export default function PowershellCommands() {
<Paragraph copyable code editable ellipsis={true}>
{envVar_cmd}
</Paragraph>
<Divider dashed />
<Title level={4}>HTTP download (wget like)</Title>
<Divider orientation='center'>HTTP download (wget like)</Divider>
<Paragraph copyable code editable ellipsis={true}>
{powershell_http_dl}
</Paragraph>
@@ -101,8 +104,7 @@ export default function PowershellCommands() {
<Paragraph copyable code editable ellipsis={true}>
{cmd_cert_http_dl}
</Paragraph>
<Divider dashed />
<Title level={4}>WLAN enumeration</Title>
<Divider orientation='center'>WLAN enumeration</Divider>
{wlan_creddump.map( ( k, i ) => {
return (
<Paragraph key={i} copyable code editable ellipsis={true}>
@@ -112,20 +114,18 @@ export default function PowershellCommands() {
} )}
</div>
<Divider dashed />
<Divider orientation='center'>Active Directory enumeration</Divider>
<div
key='b'
style={{
padding: 15
}}
>
<Title level={2}>Active Directory enumeration</Title>
<Paragraph>Require Powerview.ps1</Paragraph>
<Paragraph copyable code editable ellipsis={true}>
{power_view_repo}
</Paragraph>
<Title level={4}>Domain enumeration</Title>
<Text strong># Domain enumeration</Text>
<Paragraph copyable code editable ellipsis={true}>
{domain_name}
</Paragraph>
@@ -155,18 +155,14 @@ export default function PowershellCommands() {
{domain_trust}
</Paragraph>
<Divider dashed />
<Title level={4}> GPO enumeration</Title>
<Divider orientation='center'>GPO enumeration</Divider>
<Text strong># GPO applied to the machine</Text>
<Paragraph copyable code editable ellipsis={true}>
{gpo_enum}
</Paragraph>
<Divider dashed />
<Title level={4}> Password enumeration</Title>
<Divider orientation='center'>Password enumeration</Divider>
<Text strong># Last Password Set date</Text>
<Paragraph copyable code editable ellipsis={true}>
@@ -176,9 +172,7 @@ export default function PowershellCommands() {
<Paragraph copyable code editable ellipsis={true}>
{user_desc_harvest}
</Paragraph>
<Divider dashed />
<Title level={4}> Computer enumeration</Title>
<Divider orientation='center'>Computer enumeration</Divider>
<Text strong># List Computers of the Domain</Text>
<Paragraph copyable code editable ellipsis={true}>
@@ -193,9 +187,7 @@ export default function PowershellCommands() {
{domain_win7U_computers}
</Paragraph>
<Divider dashed />
<Title level={4}> Admin groups and account enumeration</Title>
<Divider orientation='center'>Admin groups and account enumeration</Divider>
<Text strong># List Domain Admin members</Text>
<Paragraph copyable code editable ellipsis={true}>
@@ -215,9 +207,7 @@ export default function PowershellCommands() {
{user_group_membership}
</Paragraph>
<Divider dashed />
<Title level={4}> ACL enumeration</Title>
<Divider orientation='center'>ACL enumeration</Divider>
<Text strong># User ACL </Text>
<Paragraph copyable code editable ellipsis={true}>
@@ -233,6 +223,16 @@ export default function PowershellCommands() {
<Paragraph copyable code editable ellipsis={true}>
{ACL_passwd_edit_rights}
</Paragraph>
<Divider orientation='center'>Local reconnaissance</Divider>
<Text strong># Export user accounts with ldifde</Text>
<Paragraph copyable code editable ellipsis={true}>
{local_recon_ldifde}
</Paragraph>
<Text strong># Export user accounts with csvde</Text>
<Paragraph copyable code editable ellipsis={true}>
{local_recon_csvde}
</Paragraph>
</div>
</QueueAnim>
);

View File

@@ -68,11 +68,8 @@ export default function ReverseShell() {
</Col>
</Row>
</div>
<Divider dashed />
<Divider orientation='center'>Bash</Divider>
<div style={{ padding: 10, marginTop: 15 }} key='a'>
<Title level={3}>
Bash <IconFont type='icon-gnubash' />
</Title>
<Paragraph code ellipsis={true}>
{bash_rshell}
</Paragraph>
@@ -95,11 +92,8 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>Zsh</Divider>
<div style={{ padding: 10, marginTop: 15 }} key='a'>
<Title level={3}>
Zsh <IconFont type='icon-command-line' />
</Title>
<Paragraph code ellipsis={true}>
{zsh_rshell}
</Paragraph>
@@ -122,11 +116,8 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>Netcat</Divider>
<div style={{ padding: 10, marginTop: 15 }} key='b'>
<Title level={3}>
Netcat <IconFont type='icon-command-line' />
</Title>
<Paragraph code ellipsis={true}>
{netcat_rshell}
</Paragraph>
@@ -149,7 +140,7 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>PHP</Divider>
<div
key='c'
style={{
@@ -157,9 +148,6 @@ export default function ReverseShell() {
marginTop: 15
}}
>
<Title level={3}>
PHP <IconFont type='icon-php' />
</Title>
<Paragraph code ellipsis={true}>
{php_rshell}
</Paragraph>
@@ -184,11 +172,8 @@ export default function ReverseShell() {
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>PowerShell</Divider>
<div style={{ padding: 10, marginTop: 15 }} key='a'>
<Title level={3}>
PowerShell <IconFont type='icon-powershell' />
</Title>
<Paragraph code ellipsis={true}>
{PS_rshell}
</Paragraph>
@@ -218,10 +203,7 @@ export default function ReverseShell() {
marginTop: 15
}}
>
<Divider dashed />
<Title level={3}>
Perl <IconFont type='icon-perl' />
</Title>
<Divider orientation='center'>Perl</Divider>
<Paragraph code ellipsis={true}>
{perl_rshell}
</Paragraph>
@@ -245,7 +227,7 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>Python</Divider>
<div
key='e'
style={{
@@ -253,9 +235,6 @@ export default function ReverseShell() {
marginTop: 15
}}
>
<Title level={3}>
Python <IconFont type='icon-python' />
</Title>
<Paragraph code ellipsis={true}>
{python_rshell}
</Paragraph>
@@ -279,7 +258,7 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>Ruby</Divider>
<div
key='f'
style={{
@@ -287,9 +266,6 @@ export default function ReverseShell() {
marginTop: 15
}}
>
<Title level={3}>
Ruby <IconFont type='icon-ruby' />
</Title>
<Paragraph code ellipsis={true}>
{ruby_rshell}
</Paragraph>
@@ -313,11 +289,8 @@ export default function ReverseShell() {
</Button>
</Clipboard>
</div>
<Divider dashed />
<Divider orientation='center'>Telnet</Divider>
<div style={{ padding: 15, marginTop: 15 }} key='g'>
<Title level={3}>
Telnet <IconFont type='icon-lvzhou_yuanchengTelnet' />
</Title>
<Paragraph code ellipsis={true}>
{telnet_rshell}
</Paragraph>

View File

@@ -275,7 +275,7 @@ export default function PhpReverseShell() {
</Button>
</Clipboard>
</div>
<Divider orientation="left">Basic RCE</Divider>
<Divider orientation="center">Basic RCE</Divider>
<div
key='b'
style={{
@@ -316,7 +316,7 @@ export default function PhpReverseShell() {
</Button>
</Clipboard>
</div>
<Divider orientation="left">Web Shell</Divider>
<Divider orientation="center">Web Shell</Divider>
<div
key='c'
style={{
@@ -352,7 +352,7 @@ export default function PhpReverseShell() {
</a>
</Button>
</div>
<Divider orientation="left">Obfuscated PHP Web Shell</Divider>
<Divider orientation="center">Obfuscated PHP Web Shell</Divider>
<div
key='d'
style={{

View File

@@ -0,0 +1,7 @@
import styles from './dark-compact.theme.less';
import { useApplyStyles } from '../theming';
export default function DarkTheme () {
useApplyStyles( styles );
return null;
}

8
src/themes/DarkTheme.tsx Normal file
View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import styles from './dark-compact.theme.less';
import { useApplyStyles } from '../theming';
export default function DarkTheme () {
useApplyStyles( styles );
return null;
}

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import styles from './light-compact.theme.less';
import { useApplyStyles } from '../theming';
export default function LightCompactTheme () {
useApplyStyles( styles );
return null;
}

View File

@@ -0,0 +1,8 @@
import * as React from 'react';
import styles from './light.theme.less';
import { useApplyStyles } from '../theming';
export default function DarkTheme () {
useApplyStyles( styles );
return null;
}

View File

@@ -0,0 +1,6 @@
@import '../../node_modules/antd/dist/antd.dark.less';
@import '../../node_modules/antd/dist/antd.compact.less';
.site-layout .site-layout-background {
background: #0f0f0f;
border-radius: 10px;
}

View File

@@ -0,0 +1,5 @@
@import '../../node_modules/antd/dist/antd.dark.less';
.site-layout .site-layout-background {
background: #0f0f0f;
border-radius: 10px;
}

29
src/themes/index.ts Normal file
View File

@@ -0,0 +1,29 @@
import { lazy } from 'react';
import { Theme } from '../theming/types';
export const themes: Theme[] = [
{
id: 'light', // used as value in the select
displayName: 'Light', // used as label in the select
filename: 'light.theme.less',
component: lazy(() => import('../themes/LightTheme'))
},
{
id: 'lightCompact',
displayName: 'Light Compact',
filename: 'light.theme.less',
component: lazy(() => import('../themes/LightCompactTheme'))
},
{
id: 'dark',
displayName: 'Dark',
filename: 'light.theme.less',
component: lazy(() => import('../themes/DarkTheme'))
},
{
id: 'darkCompact',
displayName: 'Dark Compact',
filename: 'light.theme.less',
component: lazy(() => import('../themes/DarkCompactTheme'))
}
];

View File

@@ -0,0 +1,9 @@
@import '../../node_modules/antd/dist/antd.compact.less';
.site-layout .site-layout-background {
background: #fff;
border-radius: 10px;
}
.ant-divider-dashed {
border-color: rgba(0, 0, 0, 0.20);
}

View File

@@ -0,0 +1,9 @@
@import '../../node_modules/antd/dist/antd.less';
.site-layout .site-layout-background {
background: #fff;
border-radius: 10px;
}
.ant-divider-dashed {
border-color: rgba(0, 0, 0, 0.20);
}

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import { Spin, SpinProps } from 'antd';
import { LoadingOutlined } from '@ant-design/icons';
export default function LoadingIndicator ( props: SpinProps ) {
return (
<div
style={{
height: '100%',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -520%)'
}}>
<Spin indicator={<LoadingOutlined />} {...props} />
</div>
);
}

26
src/theming/index.tsx Normal file
View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import { Suspense, useEffect } from 'react';
import { LazyStyle, Theme } from './types';
import LoadingIndicator from './LoadingIndicator';
export function useApplyStyles ( styles: LazyStyle ): void {
useEffect( () => {
styles.use();
return () => styles.unuse();
} );
}
interface DynamicThemeProps {
themes: Theme[],
value: string,
}
export default function DynamicTheme ( { themes, value }: DynamicThemeProps ) {
const Component = themes.find( theme => theme.id === value )?.component;
return (
<Suspense fallback={<LoadingIndicator tip="loading" />}>
<Component />
</Suspense>
);
}

13
src/theming/types.ts Normal file
View File

@@ -0,0 +1,13 @@
import { ReactNode } from 'react';
export interface LazyStyle {
use: () => void;
unuse: () => void;
}
export interface Theme {
id: string;
displayName: string;
filename: string;
component: ReactNode;
}

View File

@@ -2,13 +2,27 @@
"compilerOptions": {
"jsx": "react",
"module": "commonjs",
"allowSyntheticDefaultImports": true,
"noImplicitAny": false,
"outDir": "./dist/",
"preserveConstEnums": true,
"removeComments": true,
"esModuleInterop": true,
"baseUrl": "src",
"sourceMap": true,
"target": "es5",
"moduleResolution": "node",
"target": "es6",
"paths": {
"compforms": [
"compforms"
],
"components": [
"components"
],
"utils": [
"utils"
]
}
},
"include": [
"./src/**/**/*"

View File

@@ -3,6 +3,16 @@ const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const lessLoader = {
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true
}
}
};
module.exports = {
mode: 'development',
@@ -14,6 +24,7 @@ module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(),
new ReactRefreshWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'Output Management',
template: './src/index.html'
@@ -70,11 +81,11 @@ module.exports = {
loader: 'ts-loader',
exclude: /node_modules/
},
{
/* {
test: /\.css$/,
include: path.resolve(__dirname, 'src'),
use: [ 'style-loader', 'css-loader' ]
},
}, */
{
test: /\.(png|svg|jpg|gif)$/,
include: path.resolve(__dirname, 'src'),
@@ -84,6 +95,22 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)$/,
include: path.resolve(__dirname, 'src'),
use: [ 'file-loader' ]
},
{
test: /\.theme\.(less|css)$/i,
use: [
{
loader: 'style-loader',
options: { injectType: 'lazyStyleTag' }
},
'css-loader',
lessLoader
]
},
{
test: /\.(less|css)$/,
exclude: /\.theme\.(less|css)$/i,
use: [ 'style-loader', 'css-loader' ]
}
]
}